Appearance
(c) Matthias Meier, Manuel Di Cerbo
4. Buildroot Deployen
Übersicht zu Komponenten und Versionen
Name | Version | Link |
---|---|---|
Ubuntu | 22.04 LTS | link |
Raspberry Pi OS | Raspberry Pi OS Lite | link |
Linux Kernel | rpi-6.6.y | link |
ARM gcc Toolchain | 13.2.Rel1 | link |
Virtualbox | 7.0.18 | link |
Buildroot | 2024.02.2 | link |
Buildroot Image auf die SD flashen
Beim letzten Versuch haben Sie das Buildroot Image konfiguriert und erstellt, weswegen Sie unter ~/esl/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: ~/esl/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 umount
:
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 perchown
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)
Datei | Zweck |
---|---|
/etc/inittab | Der 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/rcS | Ein 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/rcK | Shell Script, welches beim Herunterfahren alle Scripts unter /etc/init.d/S* in umgekehrter alphanumerischer Reihenfolge mit Argument 'stop' ausführt. |
/etc/fstab | Definiert 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/interfaces | Konfiguration der Netzwerkinterfaces - z.B. Loopbackinterface, Ethernet, WLAN etc. (Beim Starten via systemd oder graphischer Oberfläche woanders definiert) |
/etc/hostname | Name 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/issue | identifiziert den OS-Release (vom System nicht benötigt) |
/etc/nsswitch.conf | In 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/passwd | Zuweisung von User-Namen zur nummerischen UIDs, Homeverzeichnis etc. (derzeit nebst dem "echtem" User root bloss noch Pseudouser für diverse Dienste). |
/etc/group | In dieser Datei erfolgt die Zuweisung von Group-Namen zu GID sowie die zuweisung sekundärer Gruppenmitgliedschaften (vgl. Ausgabe von id ). |
/etc/shadow | Passwort-Hashes zu /etc/passwd (Da Passwort-Hashes kritisch sind sollten normale User und Dienste auf diese Datei keine Leserecht haben!!) |
/etc/hosts | Statische Auflösung von IP-Adressen zu Namen - normalerweise wird nur localhost sowie der eigene Hostname definiert, der Rest erfolgt via DNS. |
/etc/protocols, /etc/services | Zuweisung von Internet-Protokollnamen zu Nummern (z.B. tcp: 6) sowie IP-Portnamen zu Nummern (z.B. http: 80) (vgl. /etc/nsswitch.conf ) |
/etc/profile, ~/.profile | Shell 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.cache | Aus 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.conf | Wireless Konfiguration (standardmässig nicht aktiv) |
/etc/dropbear/ dropbear_ecdsa_host_key | Beim 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 ~/esl/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 wieps
,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. Dadevtmpfs
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:
- Bei "Meldungs-Überflutung" findet eine unnötige hohe Abnutzung des Flash-Speichers statt!
- 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:
- Via Ethernet über ein vorhandenes LAN und IP-Adresse per DHCP beziehen
- Via WiFi über einen WiFi Accesspoint (z.B. auf einem NAT-Router und IP-Adresse per DHCP)
- Über eine Ethernet-Direktverbindung zum PC/Notebook mit IP-Adresse per DHCP vom PC
- Ü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 Commandifup -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:
- Die Verbindung zum Board via USB-Ethernet-Adaper sollte nun ja bestehen, d.h. ein Pingen des Wandboards vom Linux-Hostsystem aus sollte klappen.
- 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 viapicocom
mittels Commandpasswd
entweder ein eigenes einfaches Passwort oder durch zweimaliges<enter>
ein leeres Passwort. (Wir hätten natürlich in der Buildrootmenuconfig
auch ein Passwort vergeben können...) - 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 viassh
gestarteten Shell können Sie wieder zum Hostsystem zurückkehren. - 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 Zielsystem | Verwendung |
---|---|
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:(Achtung: Es ist kein Leerschlag nach der IP zulässig!)/srv/nfs 192.168.254.254(rw,sync,no_root_squash,no_subtree_check)
- 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 ParameterTFTPD_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...