Skip to content
On this page

(c) Matthias Meier, Manuel Di Cerbo

4. Buildroot Deployen

Buildroot Image auf die SD flashen

Beim letzten Versuch haben Sie das Buildroot Image konfiguriert und erstellt, weswegen Sie unter ~/embedded-linux/buildroot/output/images/ u.a. die Datei sdcard.img finden sollten.

Im Folgenden soll sowohl das Kopieren des Images auf die SD als auch später die Serielle UART- als auch Netzwerk-Verbindung zum Zielsystem vom Linux-Entwicklungssystem aus erfolgen (denn Sie sollten diese Vorgänge im Rahmen dieses Unterrichts ja kennen lernen! Arbeiten Sie deshalb nicht direkt vom Windows- oder OS-X Hostsystem aus, es sei denn, USB will unter dem Linux-Gastsystem par tout nicht funktionieren.)

Auch wenn Ihr PC einen SD-Karten-Slot haben sollte, verwenden Sie bei einem virtualisierten Linux besser den USB SD-Card Reader, denn auf diesen kann vom Gastsystem aus einfacher zugegriffen werden.

Stecken Sie die SD-Micro Karte direkt (falls nötig über den passiven Micro-SD-Adapter) in SD-Card-Reader ein und diesen dann an den PC und reservieren Sie diesen für das Gastsystem über das Gastsystem-Menu: Geräte > USB.

Geben Sie danach im Gastsystem das Kommando lsblk ein, wonach sich die SD-Karte zeigen sollte. Auf einem virtualisierten Linux ist die SD-Karte normalerweise der zuletzt angezeigte sdX Device, also vermutlich sdb, denn sda ist ja (vermutlich) die virtuelle Disk mit dem RFS.

Aufpassen beim flashen

Validieren Sie immer die Grösse des Devices bevor Sie ein Image auf einen Datenträger schreiben, denn bei Angabe eines falschen Ziels überschreiben Sie womöglich die (virtuelle) Systemdisk samt Benutzerdaten!

Die erwartete Grösse ist bei einer SD-Karte ca. 5..10% geringer als die spezifizierte Grösse, also etwa 30GB bei einer 32GB SD-Karte. Beachten Sie auch den Unterschied zwischen Disk und Partition! Beispielsweise bezeichnet sdb (bei Verwendung eines USB SD-Cardreaders) oder mmcblk0 (bei einem fest verbauten MMC/SD-Slot am Notebook oder beim Raspi) die gesamte SD (also alle Raw Sektoren), wogegen sdb1 resp. mmcblk0p1 jeweils die erste Partition auf der betreffenden SD Disk referenziert (also nur die Sektoren der betr. Partition)!

Blockweise kopieren

Im Folgenden wird davon ausgegangen, dass die SD als sdb erkannt wurde! (Berücksichtigen Sie dies, im Falle Sie auf einem nicht-virtualisierten Linux arbeiten!)

  • Erkannte SD-Karten-Partition(en) werden bei den meisten Distributionen automatisch gemountet, bei Ubuntu unter /media/<ihre-user-id>
  • Ein Neubeschreiben/Neupartitionieren/Neuformatieren sollte nie im gemounteten Zustand erfolgen!

Unmounten Sie deshalb allfällig gemountete Partitionen z.B. per:

bash
sudo umount /media/$USER/*

Umgebungsvariablen

$USER ist eine Umgebungsvariable und wird durch die Shell mit dem zugewiesenen Wert substituiert.

Schauen Sie sich mit env alle Umgebungsvariablen an.

Um beim login ins System eine Umgebungsvariable einzurichten, können Sie diese in ~/.brash_profile anlegen.

bash
#~/.bash_profile

export MEINE_VARIABLE=123

Im Terminal können Sie eine Variable auch einfach mit export erstellen, diese wird aber nur im aktuellen Terminal verfügbar sein.

Manachmal ist es in einem solchen Fall hilfreich ein Skript zu erstellen, welches Variablen für ein Terminal exportiert. Hierzu können Sie ein normales BASH Script mit export Statements erstellen und dieses via source laden.

Beispiel:

bash
source ~/.bash_rc # lädt alle variablen, welche exportiert wurden
. ~/.bash_rc # . ist kurz für source

Um die SD-Karte Blockweise zu beschreiben verwenden wir dd.

Partitionen Löschen

Löschen Sie dann sicherheitshalber wie folgt die ersten 10 Megabytes der SD-Karte und dadurch eine allenfalls vorhandene Partitonstabelle:

bash
sudo dd if=/dev/zero of=/dev/sdb bs=1M count=10
sync

sync

sync schreibt alle pendenten Blöcke aus und blockiert das Terminal solange.

Image flashen

Danach Schreiben Sie das per Buildroot erstellte Image auf die SD "Disk" per:

Wechseln Sie ins Verzeichnis des images mit: cd ~/embedded-linux/buildroot/output/images/

bash

sudo dd if=sdcard.img of=/dev/sdb bs=4M oflag=sync status=progress

zu schnell kopiert

Das Kopieren dauert etwa eine Minute. Sollte es nur etwa eine Sekunde dauern, haben Sie das Image nur eine lokale Datei des Hostsystems kopiert, statt auf den Devicenode der SD!

Studieren Sie in der Zwischenzeit nach Eingabe von man dd die oben aufgeführten Argumente von dd.

Nach dem Flashen immer sync und unmount:

bash
sync
sudo umount /media/$USER/*

Auf der SD-Karte existieren nun zwei Partitonen:

  • Boot: Beinhaltet Kernel, Bootloader Config und Kernel Command Line
  • Root File System (RFS): Beinhaltet den Userspace

Seriale Verbindung zum Zielsystem

Für folgende Schritte können Sie den "Sense-Hat" vom Raspberry Pi wieder entfernen, da wir auf die Serielle Schnittstelle angwiesen sind. Sobald wir eine solide Ethernetkonfiguration etabliert haben, können wir via SSH aufs Target zugreifen und sind nicht mer dringen auf UART angewiesen.

Stecken Sie den USB-Serial Adapter an den PC und reservieren Sie diesen Adapter über das Gastsystem-Menu Devices > USB > FTDI FT232R USB UART

Mit einem ls /dev/tty* sollte dann ein Eintrag /dev/ttyUSB0 ersichtlich sein.

Namen von Seral Adaptern

/dev/ttyUSB* ist typisch für FTDI-Chip basierte Serial-Devices, wogegen /dev/ttyACM* für USB CDC-ACM Deviceclass komp.

Als "Terminal Emulator" verwenden wir das Console Programm picocom (besser und einfacher als alle Alternativen unter der grafischen Oberfläche! Einzige ausnahme: minicom) .

Versuchen Sie picocom dann mit 115200 Baud zu starten:

bash
picocom -b 115200 /dev/ttyUSB0

Permission denied beim Zugriff auf /dev/ttyUSB0

Vermutlich wird Zugriff auf den Devicenode /dev/ttyUSB0 mit "Permission denied" verweigert! Ihre User-Id (unter welcher picocom gestartet wurde) hat also keine Zugriffsrechte auf diesen Devicenode.

Statt jedesmal picocom über sudo zu starten (und dann das Passwort einzugeben) oder gar in einer root-Shell zu arbeiten (was man generell nie machen sollte!), geben Sie besser Ihrer User-Id die fehlende Berechtigung:

Betrachten Sie hierzu die "Permissions" dieses Devicenodes per ls -l /dev/ttyUSB0.

Der "Eigentümer" ist gemäss dem 3. Feld offensichtlich root und das 4. Feld bezeichnet wiederum die group names, welche gemäss dem 1. Feld auch read- und write-Permission hat.

Fügen Sie Ihrer User-Id also die betreffende Gruppenmitgliedschaft hinzu: (Annahme: group = xxxxx)

bash
sudo usermod -a -G xxxxx $USER
# (Anm: solange Sie nicht in einer Root-Shell arbeiten, ist $USER Ihre UID)

Achtung!!! das -a nicht vergessen, sonst verlieren Sie das sudo-Recht und dann lässt sich das System bloss noch über die Recovery-Console retten!

Um die neue Gruppenmitgleidschaft zu aktivieren, müssen Sie aus dem Linux System aus- und neu einloggen.

Nach dem Einstecken des Raspi-Netzteils sollte der Linux-Kernel nach einer Weile booten, das Root- filesystem mounten sowie den 1. Prozess (/sbin/init) starten worauf der Login-Prompt angezeigt wird.

Der user ist root, ohne Passwort.

Im Fehlerfall (also wenn der Kernel das Rootfilesystem nicht mounten oder den init Prozess nicht starten kann), endet der Kernel mit einer Meldung "Kernel panic ..."

Gegebenenfalls versuchen Sie das Problem mittels angezeigtem Kernel-Log zu lokalisieren - vermutlich haben Sie einen Fehler bei der Buildroot menuconfig oder beim Aufspielen des Images gemacht.

Buildroot Systemkonfiguration studieren

Studieren Sie nochmals den Kernel Log! Sie können diesen auch nachträglich wieder anzeigen per:

bash
dmesg

Nach Initialisierung von CPU, Memory und SoC-interner Peripherie sind folgende Meldungen gegen Ende des Kernellogs beachtenswert:

VFS: Mounted root (ext4 filesystem) readonly on device 179:2.


...


Run /sbin/init as init process

VFS

VFS ist die Abkürzung für "Virtual File System" und "root" bezieht sich auf das Rootfilesystem und nicht auf den root User!

Aber was ist wohl der aufgeführte device 179:2 und woher weiss der Kernel überhaupt was er mounten soll?

Mit cat /proc/cmdline werden die Bootparameter angezeigt, welche der Bootloader dem Kernel übergeben hat.

Darin wurde mit root=... dem Kernel angegeben, was er als Rootfilesystem mounten soll - gemäss dem Bootparameter root offensichtlich /dev/mmcblk0p2.

Gemäss cat /proc/devices entspricht mmcblk0p2 wiederum dem Major Node 179 und Minor Node 2, also die 2. Partition von mmcblk0 resp. der SD Karte. (Die 1. Partition ist die boot Partition.)

Auch ein ls -l /dev/mmcblk0p2 bestätigt diese Major- und Minor Node Ids (vgl. 5. und 6. Feld)

Gerätetreiber in Linux

Auf Linux-Systemen werden normalerweise unter dem Verzeichnis /dev so genannte Devicenodes angelegt. Diese dienen in erster Linie als Bindeglied zwischen (Usermode-)Programmen (inkl. Dienst-Programmen) und den Gerätetreibern im Linux-Kernel, von und auf welche ein Programm lesen oder schreiben möchte.

Ein Devicenode ist also kein Treiber, sondern identifiziert diesen bloss mithilfe zweier numerischen IDs, genannt Major Number und Minor Number ein Device:

  • die Major Number dient als Treiber-Id, unter welcher sich der Treiber beim Kernel registriert
  • die Minor Number wird hingegen meist treiberspezifisch verwendet, sodass der betreffende Treiber selbst nochmals zwischen verschiedenen Ressourcen unterscheiden kann,im Falle eines Disk-Treibers z.B. zur Unterscheidung der Disk-Partitionen oder bei einem Serielle Schnittstellentreiber für mehrere Adapter.

Wenn ein Treiber die Minor Number nicht oder nur teilweise benötigt, können sich auch mehrere Treiber unter Verwendung der gleichen Major Number diese Major Number teilen.

Insbesondere ist dies bei der Major Number 10 (misc) der Fall, welche für "Kleinkram" Treiber reserviert ist. Umgekehrt kann sich ein und derselbe Treiber auch unter mehreren Major Numbers registieren, sofern der Minor Bereich nicht ausreicht.

Die Zuordnung der Treiber zu den Major-Nummern kann man wie gezeigt mit cat /proc/devices einsehen:

Major-Nummern von 254 rückwärtszählend sind dabei dynamisch vom Kernel zugeordnet, die anderen sind hingegen statisch d.h. direkt im betreffenden Treiber "hardcodiert".

In den Verzeichniseinträgen (inodes) von Devicenodes (unter /dev) wird nebst Major- und Minor-Nummer auch die Zugriffsrechte auf das Device definiert (d.h. Read-/Write-/Execute-Rechte auf Owner, Group und Others) sowie im 1. Zeichen des 1. Feldes der Devicetyp: b=Blockdevice also für blockweise adressierbare resp. im Dateisystem mountbare Geräte wie Harddisks, Memorysticks, etc oder c=Characterdevice für Streamorientierte Devices wie serielle Schnittstellen, Soundkarten etc. etc.

Die Zuordnung von Owner- und Group Permission auf dem Devicenode erstellt der Kernel hingegen immer als root:root. Will man dies ändern, so ist dies nur im "Userspace" möglich...

Betrachten Sie die Devicenodes auf dem Zielsystem unter /dev mittels:

bash
ls -l /dev

Wie Sie erkennen ist die Überzahl der Devices Characterdevices und nur wenige sind Blockdevices.

Lesen Sie hierzu noch auf https://buildroot.org/downloads/manual/manual.html im Kapitel 6.2. /dev management, welche Möglichkeiten Buildroot bietet, um die Devicenodes zu erstellen!

Welcher auffallende Unterschied der "Permissions" ist auf dem Zielsystem gegenüber dem Hostsystem ersichtlich (auf beiden Systemen ls -l /dev )?

Permissions für Gerätetreiber zur laufzeit anpassen

Das Korrigieren von "Permissions" und/oder ausführen von Aktionen - z.B. beim Anstecken eines USB-Stick erfolgt auf dem Hostsystem über den udev Mechanismus, welcher in das Init-Sytem systemd integriert ist (systemd-udev).

Da wir jedoch auf dem Zielsystem nicht systemd verwenden sondern das viel einfachere Busybox init, wird keine automatische Korrektur der Permission vorgenommen: alle Einträge haben root als "owner" als auch "group".

Will man dies bei Buildroot ändern, gäbe es folgende Möglichkeiten:

  • entweder auf dem Zielsystem den Koloss systemd verwenden (nicht empfohlen)
  • oder Verwendung des einfachen Busybox Hotplug-Deamons mdev und anpassen der Datei: /etc/mdev.conf (vgl. https://git.busybox.net/busybox/tree/docs/mdev.txt )
  • oder sofern nur wenige Device Nodes korrigiert werden sollen am Einfachsten mittels zusätzlichen sysinit Einträgen in /etc/inittab, in welchen per chown Command die Korrekturen vorgenommen werden. (Die Datei /etc/inittab werden Sie gleich kennen lernen ...)

Minimales Linux

Versuchen Sie entweder selbständig oder wie folgt die Systemkonstellation näher kennen zu lernen.

Ein ps auf dem Zielsystem zeigt, dass abgesehen von vielen Kernel-Prozessen (erkennbar an den eckigen Klammern [...] ), nur wenige Usermode-Prozesse laufen. Usermode-seitig läuft das System also wirklich sehr schlank! (Auf Ihrem Linux- Hostsystem laufen hunderte Prozesse und unter Windows zeigt der Windows Taskmanager diese schon gar nicht an!)

Vergleichen Sie ps aux auf dem Hostsystem mit dem Target.

Weiter zeigt ein ls -l /bin /sbin /usr/bin /usr/sbin dass die meisten Programme bloss symbolische Links (resp. "Symlinks") auf das Binary /bin/busybox sind - effektiv also im busybox Binary implementiert sind! Nur die in der Busybox menconfig manuell zugefügten "Tools" wie dropbear und nano sowie die Wireless Tools sind richtige "Binaries". Die Busybox-Commands sind aber generell nicht so leistungsfähig wie die gleichnamigen Commands auf dem Hostsystem, unterstützen also meist fast keine Optionen (vgl. z.B. ps --help auf Host- und Zielsystem).

Auch man Pages existieren zu den Busybox Commands nicht - bestenfalls jeweils Kurzhilfe mittels Programm-Argument --help . Auch die Doku auf https://git.busybox.net/busybox/tree/docs/ ist spärlich. Etwas mehr Info findet man noch im Busybox Sourcecode unter https://git.busybox.net/busybox/tree/.

Ein ifconfig zeigt weiter, dass sowohl das Loopback-Interface lo als auch das das Ethernet Netzwerk Interface eth0 konfiguriert ist. Nur wenn Sie ein Ethernet-Kabel zu Ihrem Heim-LAN bereits beim Booten angesteckt hatten, wird automatisch eine IP bezogen.

Ein mount zeigt weiter, dass das Root-Filesystem tatsächlich vom Typ ext4 ist, jedoch ist nicht mehr ersichtlich, welche Partition hierfür eingebunden wurde (da der Kernel das Rootfilesystem eingebunden hat - der vollwertige mount Befehl auf dem Hostsystem ist diesbezüglich schlauer) . Bekanntlich finden Sie diese Info ja aber in den Bootparametern unter /proc/cmdline.

Die Systemkonfiguration einigermassen POSIX-konformer Systemen ist üblicherweise unter /etc Lassen Sie auf dem Zielsystem alle Dateien unter /etc auflisten per: find /etc -type f

Studieren Sie die folgende Tabelle und betrachten/studieren Sie auf dem Zielsystem alle in der Tabelle fett angegebenen Dateien! (Die Tabelle ist in der Reihenfolge, wie diese vom System verwendet werden geordnet)

DateiZweck
/etc/inittabDer vom Kernel gestartete Prozess /sbin/init interpretiert als allererstes diese Datei /etc/inittab. Dies deutet darauf hin, dass unser System ein halbwegs SysV kompatiblen Bootvorgang durchführt (s.a. graue Textbox unten)!
/etc/init.d/rcSEin vom init Prozess aufgrund eines sysinit Eintrages in /etc/inittab beim Booten ausgeführtes Shell Script, welches in einer for Schleife alle Startscripts unter mit Bezeichnung /etc/init.d/S* in alphanumerischer Reihenfolge und mit Argument 'start' ausführt...
/etc/init.d/S*Start-Scripts um verschiedene Systemdienste zu starten (oder zu stoppen). Man kann diese Scripts auch manuell ausführen (mit Option start resp. stop)
/etc/init.d/rcKShell Script, welches beim Herunterfahren alle Scripts unter /etc/init.d/S* in umgekehrter alphanumerischer Reihenfolge mit Argument 'stop' ausführt.
/etc/fstabDefiniert welche zusätzlichen Partitionen beim Booten wohin (d.h. auf welchen Mountpoint) gemountet werden.Da teils die Reihenfolge wichtig ist, werden einige davon in /etc/inittab explizit gemountet, der Rest dann mittels mount -a (wobei -a für all steht)
/etc/network/interfacesKonfiguration der Netzwerkinterfaces - z.B. Loopbackinterface, Ethernet, WLAN etc. (Beim Starten via systemd oder graphischer Oberfläche woanders definiert)
/etc/hostnameName des Hosts (bei Änderung muss ev. auch /etc/hosts nachgeführt werden!). Der Hostname wird dem Kernel dann über einen sysinit Eintrages bekannt gemacht
/etc/os-release, /etc/issueidentifiziert den OS-Release (vom System nicht benötigt)
/etc/nsswitch.confIn dieser Datei wird definiert, in welcher Reihenfolge und mittels welcher Mechanismen die Namensauflösung von Usernamen, Netzwerknamen Protokollnamen etc. durch die glibc erfolgen soll. Ein Blick in diese Datei zeigt, dass dies vorwiegend durch Dateien erfolgt (insbesondere beim Login die Passwortabfrage durch /etc/passwd, /etc/group und /etc/shadow) und bei der Netzwerknamensauflösung zuerst über die Dateien (/etc/hosts etc.) und erst dann via DNS-Abfrage übers Netz. (Vgl. nsswitch.conf Hostsystem sowie man pages!)
/etc/passwdZuweisung von User-Namen zur nummerischen UIDs, Homeverzeichnis etc. (derzeit nebst dem "echtem" User root bloss noch Pseudouser für diverse Dienste).
/etc/groupIn dieser Datei erfolgt die Zuweisung von Group-Namen zu GID sowie die zuweisung sekundärer Gruppenmitgliedschaften (vgl. Ausgabe von id).
/etc/shadowPasswort-Hashes zu /etc/passwd (Da Passwort-Hashes kritisch sind sollten normale User und Dienste auf diese Datei keine Leserecht haben!!)
/etc/hostsStatische Auflösung von IP-Adressen zu Namen - normalerweise wird nur localhost sowie der eigene Hostname definiert, der Rest erfolgt via DNS.
/etc/protocols, /etc/servicesZuweisung von Internet-Protokollnamen zu Nummern (z.B. tcp: 6) sowie IP-Portnamen zu Nummern (z.B. http: 80) (vgl. /etc/nsswitch.conf)
/etc/profile, ~/.profileShell Profile: Beim Login eines Users wird von der Login-Shell zuerst die systemweite /etc/profile Datei eingelesen und damit Umgebungsvariablen wie PATH etc. definiert. Danach wird aus dem Homedirectory des Users auch die User-eigene .profile Datei eingelesen (sofern vorhanden)
/etc/ld.so.confÜblicherweise werden dynamische (shared) Libraries vom Library-Loader unter /lib und /usr/lib gesucht. Falls nötig könnten in dieser Datei weitere Verzeichnisse eingetragen werden.
/etc/ld.so.cacheAus obigem /etc/ld.so.conf könnte dann auf der binäre Library-Index-Datei mittels ldconfig erstellt werden, denn der glibc Library Loader verwendet diese Datei. (ldconfig ist auf dem Zielsystem jedoch nicht vorhanden).
/etc/wpa_supplicant.confWireless Konfiguration (standardmässig nicht aktiv)
/etc/dropbear/ dropbear_ecdsa_host_keyBeim ersten Start des SSH Deaemnon Dropbear erstellt selbiger einen zufälligen Hostkey (also den Private Key des Hosts)

Usermode Init

Wie erwähnt startet der Kernel nur einen einzigen Usermode-Prozess /sbin/init, welcher in unserem Fall die Steuerdatei /etc/inittab interpretiert.

Diese (Busybox-) Initialisierungsart ist an eine "UNIX System V Relesae 4" Initialisierung (meist kurz als "SysV Init" bezeichnet) angelehnt.

In Abweichung zu einer vollumfänglichen "SysV Init" werden aber keine "Runlevels" unterstützt, womit es nicht möglich ist, das System in verschiedene so genannte "Run-Modis" zu versetzen (wie Single User zwecks Durchführung von Mainenance-Arbeiten, Multiuser mit oder ohne grafische Oberfläche etc).

Aktuelle Linux Desktop-Distributionen verwenden keine SysVint sondern das (über-)mächtige und deshalb etwas umstrittene systemd als Initsystem, wodurch auch bei komplexen Bootkonfigurationen relativ schnell gebootet werden kann.

In der Buildroot menuconfig könnte unter "System Configuration" alternativ auch systemd ausgewählt werden.

Init Studieren

Studieren Sie den Inhalt der Zielsystem-Datei /etc/inittab , wonach Ihnen der Usermode-Initialisierungsvorgang dieses Systems einigermassen klar werden sollte!

Leider ist die Busybox-Dokumentation sowohl auf deren Homepage als auch unter den Busybox-Sourcen unter docs/ recht spärlich. Jedoch finden Sie zumindest ein eingermassen gut kommentiertes inittab Beispiel im Buildroot Source Unterverzeichnis examples/ d.h. auf ~/embedded-linux/buildroot/output/build/busybox-*/examples/inittab

Lesen Sie weiter im Buildroot Manual auf https://buildroot.org/downloads/manual/manual.html das kurze Kapitel: 6.3. init system.

Pseudofilesysteme

In Datei /etc/fstab auf dem Zielsystem finden Sie u.a folgende Mount-Einträge für so genannte Pseudofilesysteme:

# cat /etc/fstab 
# <file system> <mount pt>      <type>  <options>       <dump>  <pass>
/dev/root       /               ext2    rw,noauto       0       1
proc            /proc           proc    defaults        0       0
devpts          /dev/pts        devpts  defaults,gid=5,mode=620,ptmxmode=0666   0       0
tmpfs           /dev/shm        tmpfs   mode=0777       0       0
tmpfs           /tmp            tmpfs   mode=1777       0       0
tmpfs           /run            tmpfs   mode=0755,nosuid,nodev  0       0
sysfs           /sys            sysfs   defaults        0       0

Dass es sich dabei um Pseudofilesysteme handelt, ist an der 3. Spalte erkennbar, in welchem der Dateisystemtyp entsprechend angegeben wird.

Die erste Spalte hat bei Pseudofilesystemen hingegen keine Bedeutung (ist also bloss ein Platzhalter), weshalb diese oft als 'none' oder (rein informell) gleich lautet wie der Dateisystemtyp in der 3. Spalte.

Weitere Filesysteme

Das Einbinden weiterer Filesysteme in das vom Kernel gemountete Rootfilesystem ist prinzipiell an beliebiger Stelle im Verzeichnisbaum möglich, wobei vor dem Mounten an diese Stelle ein (leeres) Verzeichnis erstellt resp. vorhanden sein muss (=Mountpoint).

Die in /etc/fstab enthaltenen Einträge werden in unserer Konfiguration gem. /etc/inittab vom init Prozess eingebunden - zwecks korrekter Reihenfolge einige explizit, der Rest mittels mount -a

  • Das Pseudo-Filesystem proc ( "process information pseudo-file system") wird immer auf /proc gemountet. Über dieses erhält man zur Laufzeit im Usermode Informationen über den Kernel und Prozesse (viele Commands wie ps, mount etc. nutzen die unter /proc bereitgestellten Informationen).
    Weiter können auch gewisse Kernel-Eingenschaften über /proc dynamisch (also zur Laufzeit) gesetzt werden.
  • Das Pseudo-Filesystem sysfs, wird immer auf /sys gemountet und exportiert Informationen aus dem so genannten "Linux Device Tree" in den Userspace. Der Device Tree ist eine im Kernel unterhaltene Datenstruktur, in welchem alle Devices erfasst werden (vgl. The Linux Device Model 6).
    Einige (insbes. einfache) Devices können via /sys auch angesteuert werden (so z.B. LEDs ein-/ausschalten, Digitale Ein-Ausgabe, die CPU in den Standby versetzen etc.).
  • Mittels tmpfs können RAM-Disks an beliebiger Stelle im Verzeichnisbaum eingebunden werden. U.a. wird auf unserem Zielsystem eine RAM-Disk für temporäre Daten auf das Verzeichnis /tmp gemountet: diese ist schneller und verhindert unnötige Schreibvorgänge resp. Abnutzung der SD.
  • Via Pseudofilesystem devtmpfs werden in unserer Konfiguration die Devicenodes unter /dev direkt vom Kernel bereitgestellt.
    Die Einträge (Devicenodes) sind also nicht wirklich statisch auf dem Root Filesystem sondern erst bei Zugriff vom Kernel dynamisch erstellt. Die betreffende Info stammt ebenfalls aus der oben erwähnten "Linux Device Tree" Datenstruktur. Da devtmpfs gleichzeitig auch eine RAM-Disk ist, können Einträge unter /dev beliebig geändert oder ergänzt werden.

Funktioniert auf unserem System auch ein "Hot-Plugging"? Z.B. wenn Sie einen USB-Memorystick im Betrieb an das Zielsystem anstecken? Wenn ja würde dies auf der seriellen Console gemeldet!

Das Raspberry Pi verwendet bekanntlich eine separate Boot-Partition für die Boot-Dateien und Bootkonfiguration. Jedoch wird diese standardmässig nicht 'gemountet', da nur der Bootloader diese verwendet. Mit mount wird diese also nicht angezeigt, aber gemäss cat /proc/partitions muss diese wohl auf mmcblk0p1 d.h. auf der ersten Partition der SD-Karte liegen.

Ergänzen Sie in der Datei /etc/fstab (per editieren mittels nano) am Ende einen weiteren mount-Eintrag mit /dev/mmcblk0p1 als einzubindende Partition, /boot als Mountpoint, vfat als Dateisystem sowie Mountoption noauto (damit diese beim Booten nicht automatisch eingebunden wird).

Mounten Sie diese mittels mount /boot - oops da fehlt offensichtlich noch ein Ordner - korrigieren Sie's!

Wenns geklappt hat, listen Sie die Dateien unter /boot auf und studieren Sie den Inhalt der Dateien config.txt sowie cmdline.txt.

Beachten Sie, dass gemäss cmdline.txt der console Output des Kernels einerseits auf tty1, andererseits auf ttyAMA0 ausgegeben wird. tty1 ist dabei der Framebuffer eines allenfalls angeschlossen HDMI- oder LCD-Displays wogegen ttyAMA0 die angeschlossenen Serielle miniUART-Schnittstelle ist.

Wenn Sie die cmdline.txt mit dem Inhalt von /proc/cmdline vergleichen erkennen Sie weiter, dass der Bootloader selbst offensichtlich noch ein paar Parameter beisteuert, welche einige Kernel-Treibern benötigen.

Commandline Syntax

Syntax: <treibername>.<parametername>=<wert>. Dass der Kernel diese übernommen hat, ist unter /sys/modules/<treibername>/parameters/... ersichtlich.

Mittels Angabe des Kernel-Parameters init= könnte der Kernel auch ein anderer initialer Prozess an Stelle von /sbin/init starten, z.B. einfach eine Shell per init=/bin/sh. In diesem Fall erfolgt natürlich keine Initialisierung im Userspace ensprechen /etc/inittab etc!

Der Shell-Prompt auf dem Zielsystem ist mit '#' noch wenig aussagekräftig. Dieser kann aber durch Setzen der Shell-Umgebungsvariable PS1 umdefiniert werden, z.B. im Benutzer Login-Script ~/.profile welches bei Einloggen von der Login-Shell eingelesen wird. Erzeugen Sie diese Datei z.B. mittels folgendem "Einzeiler" auf dem Zielsystem aus dem Rootverzeichnis (denn root verwendet auf unserem Target selbiges als Home-Verzeichnis, wie in /etc/passwd einsehbar ist):

bash
echo "PS1='\h:\w\# '" > ~/.profile

(Achten Sie auf die korrekte Eingabe der Doppel- resp. einfachen Anführungszeichen!)

Nach Ausloggen per exit oder CTRL+D und erneutem Login sollte der gewünschte Prompt erscheinen.

Zeiteinstellung

Die Zeitangabe auf dem Zielsystem ist noch falsch, was mit Eingabe von date ersichtlich ist.

Per date -s ... könnte man zwar die Systemzeit manuell setzen, die Information geht jedoch mit jedem Reboot resp. Powerdown verloren.

Komfortabler wäre es, diese per Busybox Command hwclock Command aus einer batteriegestützten Realtime-Clock (RTC) auszulesen. Damit dies funktioniert, müsste ein geeigneter Realtime-Clock Baustein (RTC) an den I2C-Bus angeschlossen werden und das betreffende Devicetree-Overlay geladen werden (damit der Kernel weiss, welcher Baustein an welchem I2C-Bus und welche I2C-Adresse angeschlossen ist.

Alternativ kann bei vorhandenem Internet-Zugriff die Zeit auch via NTP-Protokoll mit einem Zeitserver synchronisiert werden - nach Zufügen von z.B. ntpd in der Buildroot menuconfig ...

Syslog Daemon

Der Syslog wird bei SysV konformen Systemen üblicherweise entweder auf /var/log/syslog oder wie auf unserem Zielsystem auf /var/log/messages geschrieben.

In dieser Datei werden Kernel-Meldungen wie auch sonstige System-Meldungen - also Meldungen von Usermode-Dienstprogrammen gesammelt (also all Programme, welche im hintergrund aktiv sind und keine "normale" Standard-Ein-/Ausgabe haben).

Hostseitiger syslog

Auf unserem Ubuntu existieren nebst /var/log/syslog zudem viele weitere zum Teil redundante Logfiles wie /var/log/messages, /var/log/dmesg etc. etc. sowie auch applikationensspezifische Logfiles - vgl. Ordner /var/log/

Auf Linux-Systemen mit systemd kann der System-Log hingegen mittels journalctl ausgelesen werden.

Daneben ist wie erwähnt auch das Betrachten nur des Kernel-Logs per Command dmesg jederzeit möglich.

Derartige Logfile(s) werden üblicherweise von einem "Syslog-Daemon" gesammelt, welcher in der Initialisierungsphase gestartet wird.

Busybox beinhaltet sogar einen einfachen Syslog-Daemon, jedoch ist ein Ansammeln von syslog-Meldungen gerade auf Embedded Systemen nicht ganz unproblematisch:

  1. Bei "Meldungs-Überflutung" findet eine unnötige hohe Abnutzung des Flash-Speichers statt!
  2. Sowie ein unkontrolliertes Füllen des Flash-Speichers durch das immer grösser werdende Logfile.

Ersteres lässt sich elegant lösen, indem der syslog-Daemon statt auf das Rootfilesystem auf eine RAM-Disk schreibt. Zweiteres vermeidet der Busybox-syslogd schon selbst, wie ein Blick die syslogd-Kurzhilfe zeigt: syslogd --help

In unserer Buildroot-Konfiguration scheint /var aber gemäss mount nicht auf einer Ramdisk zu sein.

Ein ls -l /var zeigt aber, dass die meisten Einträge von /var bloss Symlinks auf /tmp sind, so auch /var/log .

Das messages Logfile finden Sie somit sowohl unter /var/log/ wie auch auf /tmp/ .

In welchem Fehlerfall ist die beschriebene RAM-Disk-Lösung problematisch?

Ramdisk begrenzen

Im ungünstigsten Fall könnte ein Sturm von Logmeldungen die ganze /tmp Ramdisk füllen und damit der gesamten DRAM Hauptspeicher "aufgefressen" werden.

Dies könnte man verhindern, indem man /var/log in /etc/fstab als eigene Rasmdisk definiert und dabei per mountoption deren maximale Grösse auf wenige MB begrenzt (was bei einem tmpfs Dateisystem möglich ist).

Wo wird in unserer Bookonfiguration der syslogd gestartet? (Wenn Sie es nicht mehr wissen, werden Sie per grep -r syslogd /etc fündig!)

Netzwerk-Verbindung zum Hostsystem

Für eine effiziente Embedded System Software-Entwicklung benötigen wir eine Netzwerkverbindung zwischen dem Entwicklungsssystem (Linux-Gastsystem) sowie dem Zielsystem zwecks SSH-Zugriff.

Hierfür kommen folgende Konfigurationsvarianten in Frage:

  1. Via Ethernet über ein vorhandenes LAN und IP-Adresse per DHCP beziehen
  2. Via WiFi über einen WiFi Accesspoint (z.B. auf einem NAT-Router und IP-Adresse per DHCP)
  3. Über eine Ethernet-Direktverbindung zum PC/Notebook mit IP-Adresse per DHCP vom PC
  4. Über eine Ethernet-Direktverbindung zum PC/Notebook und statisch definierter IP-Adresse

Variante 1. sollte bei unserer Buildroot Konfiguration "Out-of-the-Box" funktionieren! Einzige Einschränkung: das automatische Beziehen der IP-Adresse funktioniert nur beim Booten.

Variante 2. Lässt sich auch relativ einfach einrichten (vgl. Anhang A: WLAN konfigurieren)

Variante 3. oder 4. drängen sich auf, wenn weder ein offenes LAN vorhanden ist (wie z.B. an der FH oder in einem grösseren Betrieb), wobei Variante 3. auf dem Gastsystem eine etwas trickreiche Internet Connection Sharing (ICS) Konfiguration voraussetzt und Variant 4. deshalb meist einfacher realisierbar ist. Im Folgenden soll desshalb Variante 4. verfolgt werden..

  • Ein ifconfig in der Seriellen Console zeigt, dass die Buildroot Initialisierung offensichtlich sowohl das Loopback Interface (lo) auch das Ethernet-Interface (eth0) aktivierte.
  • Die Konfiguration hierfür wird wie Sie erkundet haben im Init-Script /etc/init.d/S40network durch den Command ifup -a aktiviert, wobei letzteres die Konfiguration aus /etc/network/interfaces verwendet.
  • Gemäss /etc/network/interfaces wird das Ethernet-Interface automatisch gestartet und die IP-Adresse per DHCP bezogen, also automatisch vom Netz - sofern beim Booten an selbiges angeschlossen und ein DHCP Server erreichbar war.
  • Auf einem Ethernet-Interface kann man auch mehrere Konfigurationen gleichzeitig aktiv haben. Für unseren Test konfigurieren wir somit zusätzlich temporär eine statische Adresse:
bash
ifconfig eth0:1 192.168.254.254/24

Natürlich muss auch noch das Interface der Hostseite verbunden und aktiviert werden!

  • Um das "On-Board" Ethernet-Interface Ihres Notebooks nicht umkonfigurieren zu müssen soll die Ethernet-Verbindung über ein am Notebook eingestecktes USB-Ethernet-Interface realisiert werden, wobei wir auch PC-seitig mit einer fixen statischen IP-Adresse arbeiten:
  • Ermitteln Sie per Kommando 'ifconfig' vor/nach Anstecken des USB-Ethernet-Interfaces welches Interface das Ethernet-Interface ist Interface-Name: _______

Tipps

Sofern Linux als Gastsystem unter Virtualbox läuft, müssen Sie das USB-Ethernet Interface an das Hostsystem anschliessen und im Virtualbox-Menu jeweils aktivieren per: Geräte > USB-Geräte > [x] Realtek USB LAN (oder Sie reservieren diesen gleich permanent über einen "USB-Filter").

Falls dort hingegen gar keine USB-Geräte erscheinen, ist wohl USB für das Gastsystem noch nicht aktiviert (USB bei heruntergefahrener Virtueller Maschine in der Virtualbox-Management-Console aktivieren).

Das Ethernet-Interface, auf welchem (vermutlich) eine 10.x.x.x IP-Adresse definiert ist, ist ein virtuelles Ethernet-Interface zum Hostsystem. Uns interessiert jedoch das USB-Ethernet Interface!

Verbinden Sie nun noch via Ethernet-Kabel den USB-Ethernet Adapter zum Zielsystem. Ob und in welchem Mode die Verbindung auf Layer 2 (Link-Layer) funktioniert, erfahren Sie gastsystemseitig per:

bash
sudo mii-tool <interfacename>
# (den Interfacenamen haben Sie ja oben per 'ifconfig' bestimmt!)

Fügen Sie nun oben rechts über das Netzwerk-Icon → Wired Settings oder Verbindungen Bearbeiten mit Click auf das + neben Kabelgebunden ein neues Profil hinzu mit Name "USB-Ethernet (statisch)", unter MAC-Adresse wählen Sie das korrekte Interface (wie zuvor ermittelt) und konfigurieren Sie unter IPv4 darauf nach aktivieren von "Manuell" eine statische IP-Adresse 192.168.254.10 sowie Netzmaske 255.255.255.0, jedoch ohne Angabe eines Default-Gateways! (Was wäre wohl andernfalls die Folge???).

Wenn dies klappt sollte beidseitig ein ping der Gegenseite funktionieren!

Nun kann auch noch eine "permanente" IP-Konfiguration auf dem Zielsystem eingerichtet werden, sodass diese beim Booten des Zielsystems jeweils automatisch geladen wird.

Erstellen Sie also in /etc/network/interfaces einen weiteren Eintrag für eth0:1 mit folgender Config:

# falls noch nicht vorhanden im config file:
auto eth0

# eth0:1 hier
iface eth0:1 inet static
    address 192.168.254.254
    netmask 255.255.255.0

Das Editieren der Datei kann natürlich direkt auf dem Zielsystem über die Serielle Console erfolgen - mittels dem bei der Buildroot-Konfig zugefügten Editor nano (oder per vi wer diesen lieber mag ).

Danach sollte sich das Ethernet-Interface aktivieren/deaktivieren lassen per: ifup eth0:1 resp. ifdown eth0:1.

Aber startet das Interface auch automatisch nach reboot? Wenn fehlt noch was in der Config?

Übrigens, wenn Sie beim Booten das Zielsystem mit Ihrem LAN verbinden verwendet die Buildroot-Konfiguration als DHCP-Client standardmässig udhcpc , welches auch in Busybox enthalten ist.

Möchte man ein Embedded System selbst als DHCP-Server (oder z.B. als Router) verwenden, wären via Buildroot menuconfig übrigens auch diverse DHCP-Sever und/oder DNS-Server zufügbar.

Der Einfachheit halber bleiben Sie jedoch entweder bei der statischen IP-Konfiguration oder einer Verbindung über Ihr Heim-LAN mit per DHCP bezogener IP-Adresse (oder wenn Sie möchten, einer WiFi-Verbindung via wpa_supplicant).

Telnet vs. SSH

Sofern entsprechend konfiguriert, würde Busybox auch einen Telnet Daemon beinhalten. Telnet ist aber ein äusserst unsicheres Protokoll da alles, auch das Passwort im Klartext übertragen wird, weswegen hier keine "Werbung" dafür gemacht werden soll.

Eine sichere Remote-Shell ist hingegen via SSH möglich. Auf "ausgewachsenen" Systemen wird hierzu normalerweise das Open-SSH Package verwendet.

Für schlanke Embedded Systeme gibt es als Alternative das einfach Cross-compilierbare dropbear, welches wir bei der Buildroot menconfig ja schon zugefügt haben und gemäss ps bereits auch läuft.

Der Dropbear SSH Daemon benötigt wie sein Vorbild für den Host ein Private "Hostkey". Aufgrund der Option -R wird dieser bei ersten Start von dropbear automatisch generiert. Ein kurzer Test:

  1. Die Verbindung zum Board via USB-Ethernet-Adaper sollte nun ja bestehen, d.h. ein Pingen des Wandboards vom Linux-Hostsystem aus sollte klappen.
  2. Vielleicht haben Sie schon versucht, vom Hostsysteme aus per ssh root@192.168.254.254 (oder allenfalls die vom DHCP-Server Ihres LANs zugewiesenen IP-Adresse) das Zielsystem zu erreichen...

    ... es klappt nicht - und zwar weil auf dem Zielsystem noch kein root-Passwort definiert ist, denn "kein Passwort-Eintrag" (in /etc/passwd resp. /etc/shadow) ist nicht identisch mit einem definiert "leeren Passwort".

    Definieren Sie auf dem Target also via picocom mittels Command passwd entweder ein eigenes einfaches Passwort oder durch zweimaliges <enter> ein leeres Passwort. (Wir hätten natürlich in der Buildroot menuconfig auch ein Passwort vergeben können...)
  3. Danach sollte SSH funktionieren (vielleicht müssen Sie's ein paarmal versuchen oder etwas warten, denn dropbear erkennt die Änderung ev. nicht sofort). Mittels exit in der via ssh gestarteten Shell können Sie wieder zum Hostsystem zurückkehren.
  4. Ein SSH-Server (und so auch Dropbear) erlaubt zudem auch das Kopieren von Dateien oder ganze Verzeichnisse. Schauen Sie sich hierzu auf dem Hostsystem die Kurzhilfe des Commands scp an und kopieren Sie beispielsweise die Datei /tmp/messages vom Zielsystem ins /tmp/ Verzeichnis des Hostsystems und studieren sie diese Datei...

Einige wichtige Zielsystem Ordner und Dateien

Pfad auf ZielsystemVerwendung
Konfigurationsdatei für den init-Prozess
Order der Init-Scripts
Tabelle der beim Booten einzubindenden Filesysteme
Verzeichnis mit den Device Nodes
Pseudofilesystem mit Kernel-Informationen
Systemlogdatei
Netzwerk-Konfigurationsdatei

WLAN aktivieren

In der Buildroot menuconfig haben Sie bereits die nötige Firmware für den vorhandenen Broadcom WLAN-Chip zugefügt, sodass diese nun auf dem Zielsystem unter /lib/firmware/brcm/ vorhanden sein sollte!

WLAN Firmware

Insbesondere Wireless Chips benötigten nebst dem Linux-Treiber (in unserem Fall brcmfmac) meist noch eine Firmware des Chip-Herstellers, welcher üblicherweise vom betreffenden Linux-Treiber auf den WLAN-Chip geladen wird. Derartige Closed Source Firmware wird bei Linux-Systemen üblicherweise unter /lib/firmware gespeichert und ist (da ja nicht Bestandteil von Linux) Hostsystem/CPU-unabhängig.

Die nächste Hürde betrifft die Konfiguration des WLAN-Interfaces. Nach einigen Versuchen hat sich folgendes Vorgehen für "normale" (per WPA Preshared Key) gesicherte WLANs bewährt:

Ergänzen Sie auf dem Raspi-Rootfilesystem unter /etc/network/interfaces folgende Zeilen, welche zuerst den Linux-Treiber brcmfmac für den WLAN-Chip laden, danach wartet, bis der Kernel das wlan0 Interface erkennt und dann das Hilfsprogramm wpa_supplicant startet, welches die WLAN WPA-PSK-Authentifikation durchführt, danach den DHCP-Client startet:

auto wlan0
iface wlan0 inet dhcp
    pre-up modprobe brcmfmac && sleep 1 && wpa_supplicant -Dnl80211 -iwlan0 -c/etc/wpa_supplicant.conf -B
    post-down killall wpa_supplicant
    hostname buildroot-wifi

Weiter müssen Sie die Datei /etc/wpa-supplicant.conf mit folgendem Inhalt erstellen/ändern, wobei Sie "MY_SSID" und "MY_WLANKEY" natürlich entsprechend Ihrem Heim-WLAN anpassen:

#ctrl_interface=DIR=/var/run/wpa_supplicant
update_config=1
country=CH

network={
    ssid="ihre-SSID"
    psk="ihr-wlan-password"
    key_mgmt=WPA-PSK
    proto=RSN
    scan_ssid=1
}

# Achtung: die Anführungszeichen bei der SSID und dem Passwort sind zwingend nötig!

Danach sollte sich das WLAN-Interface mittels ifup wlan0 oder einem 'reboot' aktivieren lassen (kontrollieren danach mittels ifconfig den Erfolg).

WPS

Statt der manuellen SSID/Passwort-Einstellung im Abschnitt network={....} könnten dies (sofern in Buildoot zugefügt und ihr Router dies unterstützt) auch automatisch per "WiFi Push Button Configuration" erfolgen per wpa_cli -iwlan0 wps_pbc.

Eine Authentifizierung am "eduroam" Netzwerk der FHNW ist mit obiger Konfiguration hingegen nicht möglich.

(Wer sein Glück versuchen will, findet per googlen z.B. nach "eduroam wpa_supplicant.conf" sicher einen guten Einstieg - Tipp: Entweder die von der FHNW referenzierten Quovadis SSL-Zertifikate installieren oder die Zertifikatsüberprüfung abschalten!)

Zielsystem via Netzwerk-Boot booten

Fakulative Teile

Folgende Teile sind fakultativ.

Bootloader wie U-Boot oder auch der Bootloader des Raspberry Pi 4B ermöglichen nebst Booten ab Flash-Datenträger (wie SD oder eMMC) auch ein „Netzwerk-Boot“, wobei sich das „Rootfilesystem“ und optional auch der Kernel auf einem Server befindet - während der Systementwicklung z.B. auf dem Linux-Entwicklungssystem.

Beim Netzwerkboot werden keine Windows-Netzwerkfreigaben unterstützt sondern typischerweise TFTP zum Laden der zum Booten nötigen Dateien Kernel etc., sowie das NFS Protokoll („Network File System“) zum Mounten des Rootfilesystems, denn selbiges kann auch die Linux- resp. POSIX-Dateirechte abbilden. Bedenken Sie aber, dass NFS in der nachfolgenden Variante höchst unsicher ist, da keine Authentifizierung erfolgt, weshalb diese Variante nur an isolierten Netzen verwendet werden sollte.

Auf was im Folgenden nicht eingegangen wird ist die Konfiguration des Raspberry Pi Bootloaders für. Angaben hierzu finden Sie auf:

https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711_bootloader_config.md
https://www.raspberrypi.org/documentation/hardware/raspberrypi/booteeprom.md
https://www.raspberrypi.org/documentation/hardware/raspberrypi/bootmodes/bootflow_2711.md

NFS-Server einrichten

Über TFTP wird bei Diskless Boot des Zielsystems bloss der Linux-Kernel geladen - das Zielsystem benötigt jedoch auch ein „Rootfilesystem“ - vergleichbar mit dem Windows Laufwerk C . Dieses Rootfilesystem (RFS) werden wir im nächsten Versuch ebenfalls über die Ethernet-Verbindung, jedoch über das NFS (Network File System Protokoll) zur Verfügung stellen:

  • Installieren Sie den NFS-Server über das Package: nfs-kernel-server
  • Als Freigabeverzeichnis soll /srv/nfs dienen - zu konfigurieren im File /etc/exports mittels Eintrag:
    /srv/nfs 192.168.254.254(rw,sync,no_root_squash,no_subtree_check)
    
    (Achtung: Es ist kein Leerschlag nach der IP zulässig!)
  • Definieren Sie dies und studieren Sie die Parameter mittels der Hilfeseiten von: man exports
  • Starten Sie den nfs-kernel-server neu per: _______ oder per: sudo exportfs -r
  • Und kontrollieren Sie die korrekte Freigabe per: sudo exportfs
  • Auch dieser Daemon meldet Fehler in /var/log/syslog . Inspizieren Sie diesen!

Boot ab TFTP Server

Der U-Boot Bootloader des Targets unterstützt nebst Booten ab SD auch ein Booten ab Netzwerk, wobei der Linux-Kernel über TFTP (Trivial File Transfer Protokoll) von Ihrem Notebook bezogen wird.

  • Als TFTP-Server installieren Sie deshalb auf Ihrem Notebook das Package: tftpd-hpa
  • Passen Sie das per TFTP freizugebende Verzeichnis per editieren des Files: /etc/default/tftpd-hpa an (wozu natürlich wieder Root-Rechte nötig sind...):\ Den hierzu zu ändernden Parameter TFTPD_DIRECTORY retten Sie per copy&paste und auskommentieren per #. Die Kopie ändern Sie auf das gewünschte Freigabeverzeichnis: /srv/tftp

Übrigens mit TFTPD_ADDRESS=0.0.0.0:69 wird der TFTP-Daemon auf allen lokal vorhanden Interfaces auf Port 69 (dem reservierten tftp-Port) seinen Dienst zur Verfügung stellen. Aus Sicherheitsgründen könnten Sie den Zugriff statt dessen auf das USB-Ethernet-Interface beschränken, wenn Sie dessen Adresse definieren würden, also TFTPD_ADDRESS=192.168.254.10:69

Dies funktioniert jedoch nur, wenn das Ethernet-Interface bereits vor Start des TFTP-Daemons aktiv ist, was bei uns ja nicht gewährleistet ist - der TFTP-Daemon müsste deshalb jeweils nach Einloggen resp. anstecken des Interfaces neu gestartet werden.

Starten Sie aufgrund der Änderung des Freigabeverzeichnisses den TFTP-Daemon neu per:

bash
sudo /etc/init.d/tftpd-hpa restart
# (oder alternativ per 'sudo service tftpd-hpa restart' )

Anmerkung: manchmal ist statt restart auch ein explitizes stop und danach wieder start nötig.

  • Horcht der TFTP-Daemon nun auf UDP Port 69? Kontrollieren Sie's per: netstat -ln
  • Vermutlich nicht! Gibt es überhaupt einen tftpd-Prozess? Kontrollieren Sie's per: ps -ef | grep tftpd
  • Auch nicht? Auch ein Blick in den Syslog (z.B. per tail -100 /var/log/syslog oder ev. journalctl -e ) zeigt merkwürdigerweise nichts (Das Ubuntu-Team scheint das Startscript nicht ganz korrekt angepasst zu haben...).
  • Was könnte das Problem wohl sein - ja klar, das Upload-Verzeichnis fehlt - lösen Sie das Problem mittels sudo mkdir ______ und starten Sie den tftp-Daemon erneut...