Inotify ist eine Kernel-Schnittstelle zur Überwachung von Dateizugriffen, verbunden mit einem Event-Mechanismus, von dem man sich über bestimmte Ereignisse benachrichtigen lassen kann. Siehe dazu den deutschen (kurz) und englischen (ausführlich) Wikipedia-Artikel.
Die Inotify-Tools sind eine kleine Sammlung von Werkzeugen bzw. Programmierschnittstellen, um bequemer diesen mächtigen Mechanismus nutzen zu können. Wir stellen als Freetz-Paket zwei ausführbare Werkzeuge und eine Bibliothek zur Verfügung, und zwar
Verwendungsbeispiele gibt es ebenfalls auf der Sourceforge-Projektseite. Inotifywait wartet auf ein Ereignis, für das man sich vorher registriert hat und kehrt dann zurück, wenn es eintritt. Das Ganze geht auch im Hintergrundbetrieb, wenn man Ereignisse nicht nur einmalig, sondern dauerhaft beobachten möchte. Inotifywatch hingegen sammelt und summiert statistische Daten zu Dateisystem-Ereignissen und stellt sie in tabellarischer Textdarstellung zur Verfügung.
Eine besondere Anwendung, für die das Startskript rc.S
durch einen
speziellen, immer eingebauten Patch vorbereitet wird, ist das
Protokollieren sämtlicher Dateisystemzugriffe beim Starten der Box.
rc.S
ist das erste Skript, welches von init
ausgeführt wird, d.h.
die Protokollierung beginnt wirklich sehr früh (direkt nach dem Start
des Watchdogs), man verpaßt nichts Wichtiges. Da es keinen Sinn macht,
diese Protokollierung immer durchzuführen, kann man sie ein- und
ausschalten. Dafür verwendet man das [kernel_args-API?]. Vor dem zu protokollierenden Startvorgang, also vor dem Reboot,
aktiviert man die Protokollierung:
# API laden
. /usr/bin/kernel_args
# Aktivieren (Achtung, kein "=", zwei Parameter!)
ka_setValue InotifyBootAnalysis y
# Prüfen, ob Variable gesetzt
ka_getArgs
# Ergebnis z.B. idle=4 foo=bar InotifyBootAnalysis=y
Anstatt den Wert “y” kann man auch einen positiven Ganzzahlwert zuordnen, der automatisch bei jedem Start um 1 vermindert wird, bis er schließlich 0 werden würden, was zum Folgewert “n” und zur automatischen Deaktivierung der Funktion führt. So kann man erstens das Deaktivieren nicht auf Dauer vergessen und zweitens mögliche Probleme beim Hochfahren der Box durch das Logging eliminieren, indem man sie einfach oft genug neu startet, bis die Funktion wieder inaktiv ist.
Deaktivieren kann man die Funktion auch manuell, indem man in obiger Code-Sequenz eine Zeile austauscht:
# Deaktivieren
ka_setValue InotifyBootAnalysis n
Auch ganz löschen kann man die Variable aus dem Bootloader Environment:
# Variable ganz löschen
ka_removeVariable InotifyBootAnalysis
Wenn das Logging erst einmal gestartet wurde, läuft es immer weiter, bis man es manuell stoppt, nachdem der Startvorgang abgeschlossen ist bzw. auch danach noch man so viel protokolliert hat, wie man möchte. Es könnte ja sein, daß man außer dem Startvorgang noch einige Stunden oder Tage die Box weiter beobachten möchte, um festzustellen, welche Dateien überhaupt benutzt werden oder nicht, um sie dann in Verbindung mit dem Downloader-CGI auszulagern und nachzuladen oder ganz aus der Firmware zu entfernen, um Platz zu schaffen für mehr oder größere Pakete, was gerade bei Boxen mit nur 4 MB Flash-Größe eine Kunst für sich ist. Die 8-MB-Boxen sind da weniger eingeengt, aber auch dort kann es interessant sein, falls man unter “Featuritis” leidet.
Wie also stoppt man die Protokollierung, bevor einem der Speicher volläuft?
# Protokollierung anhalten
/etc/init.d/rc.inotify_tools stop
Ob die Protokollierung gerade läuft, kann man so feststellen:
# Status prüfen ("running" oder "stopped")
/etc/init.d/rc.inotify_tools status
Es ist auch jederzeit im laufenden Betrieb möglich, die Protokollierung einzuschalten, um bei Bedarf zur Laufzeit alle Dateizugriffe zu beobachten:
# Protokollierung (neu) starten
/etc/init.d/rc.inotify_tools start
Achtung, ein kleiner Ausflug ins noch Technischere: Man sollte wissen,
daß rc.inotify_tools start
eine evtl. bereits laufende Protokollierung
kurzzeitig stoppt und sie dann sofort neu startet. Das ist etwas
ungewohnt, kann aber nützlich sein in Situationen, wo Init von einem
Skript aufgrund z.B. kill -1 1
, wie rc.mini_fo
es verwendet, um in
mehreren Durchgängen sein Overlay-Dateisystem aufzuziehen, beendet wird,
um dann neu gestartet zu werden und nochmals die Startskripten
aufzurufen. Dazwischen kann die Protokollierung entweder noch laufen
oder abgebrochen worden sein. Jedenfalls startet Inotify-Tools in diesem
Fall neu, ggf. jetzt mit Ausgabe auf das frisch gemountete mini_fo
(vorher auf das nun überdeckte, darunter liegende Dateisystem).
Wir könnten alles protokollieren, aber das wäre eine große Datenmenge,
weil bestimmte Zugriffe, z.B. auf häufig verwendete Dateien wie
busybox
, uClibc
oder libcrypt
das Log zumüllen. Daß sie verwendet
werden, sollte sowieso selbstverständlich sein, und wir werden sie auch
ganz bestimmt nicht aus der Firmware auslagern. Also werden sie bei der
Protokollierung nicht berücksichtigt. So sieht in rc.S
die Passage
aus, wo die Protokollierung gestartet wird:
echo "starting inotifywait"
inotifywait -c -r -m /
@/dev @/proc @/var @/rom @/sto
--exclude 'busybox|uClibc|libcrypt-0'
>> /var/iw.log 2> /dev/null &
sleep 3
Es wird also kontinuierlich geloggt, und zwar rekursiv alles ab dem
Wurzel-Verzeichnis (“/” als Parameter am Ende der ersten
Aufruf-Zeile). Ausgeschlossen sind die virtuellen oder für interne
Mini_fo-Zwecke verwandten Verzeichnisse /dev
, /proc
, /rom
,
/sto
sowie die RAM-Disk /var
, desweiteren Dateien, welche die
Zeichenketten “busybox”, “uClibc” oder “libcrypt-0” enthalten -
die “-0” am Ende grenzt übrigens libcrypt
von libcrypto
ab.
Das Log wird geschrieben in die RAM-Disk nach /var/iw.log
- “iw” wie
“inotifywait”.
Was steht nun drin in /var/iw.log
bzw. wie sieht es aus? Ein kleiner
Ausschnitt:
/etc/,"CLOSE_NOWRITE,CLOSE",.subversion
/lib/,"CLOSE_NOWRITE,CLOSE",libgcc_s.so.1
/lib/,"CLOSE_NOWRITE,CLOSE",libgcc_s.so.1
/lib/,OPEN,libgcc_s.so.1
/lib/,ACCESS,libgcc_s.so.1
/lib/modules/2.6.13.1-ohio/modules/,DELETE_SELF,
/lib/modules/2.6.13.1-ohio/modules/,IGNORED,
/lib/modules/2.6.13.1-ohio/kernel/drivers/char/avm_event/,DELETE_SELF,
/lib/modules/2.6.13.1-ohio/kernel/drivers/char/avm_event/,IGNORED,
/lib/modules/2.6.13.1-ohio/kernel/drivers/char/avalanche_led/,DELETE_SELF,
/lib/modules/2.6.13.1-ohio/kernel/drivers/char/avalanche_led/,IGNORED,
/lib/,"CLOSE_NOWRITE,CLOSE",libgcc_s.so.1
/usr/share/images/,OPEN,edge_lt.png
/usr/share/images/,ACCESS,edge_lt.png
/usr/share/images/,"CLOSE_NOWRITE,CLOSE",edge_lt.png
Mit dem Aufruf aus rc.S
heraus wurde dafür gesorgt, daß in einem
leicht woanders (Tabellenkalkulation, Datenbank) importierbaren,
kommagetrennten CSV-Format protokolliert wird. Wie die einzelnen Daten
zu interpretieren sind, entnimmt man der Dokumentation der
Inotify-Tools, das ist nicht Freetz-spezifisch.
Falls man andere Daten sammeln möchte, z.B. Zugriffe auf die RAM-Disk
mit protokolliert haben möchte, nur ein bestimmtes Verzeichnis
beobachten möchte, nur Schreibvorgänge beobachten möchte usw., kann man
inotifywait
immer noch manuell starten oder für vorgefertigte
Statistiken auch mal inotifywatch
bemühen.
Zum Zweck des Platzsparens in Firmware-Images interessiert uns vermutlich weniger, auf welche Dateien in welcher Reihenfolge, wie oft, auf welche Weise (lesen, schreiben, anlegen, löschen etc.) zugegriffen wurde, sondern lediglich, auf welche Dateien überhaupt zugegriffen wurde - bzw. auf welche nicht, denn die würden dann im Log fehlen. Dafür wäre eine kumulierte Ausgabe praktisch, welche
usw. immer im Kreis. Folgendes Skript habe ich in meiner
/var/tmp/flash/rc.custom
, sie wird also nach dem Ende des
Freetz-Startvorgangs ausgeführt:
# Create script for continuous file access logging and log file consolidation
cat << 'EOF' > /var/tmp/iw_continuous
#!/bin/sh
# If inotify logging is inactive, start it
if [ "$(/etc/init.d/rc.inotify_tools status)" != "running" ]; then
/etc/init.d/rc.inotify_tools start
fi
MAX_LOG_SIZE=$(( 10 * 1024 ))
while true; do
sleep 60
if [[ $(( $MAX_LOG_SIZE - $(cat /var/iw.log | wc -c) )) -gt 0 ]]; then
#echo "current size of iw.log < $MAX_LOG_SIZE - continue logging"
continue;
fi
#echo "current size of iw.log >= $MAX_LOG_SIZE - consolidate file list and restart logging"
cat /var/iw.log | grep '^/' | sed 's/,.*,//' | sort | uniq | sed 's//////' > /var/iw-unique.tmp
touch /var/iw-unique.log
cat /var/iw-unique.log >> /var/iw-unique.tmp
cat /var/iw-unique.tmp | sort | uniq > /var/iw-unique.log
rm -f /var/iw-unique.tmp /var/iw.log
/etc/init.d/rc.inotify_tools start
done
EOF
chmod +x /var/tmp/iw_continuous
# If inotifywait is already running, start continuous logging script
if [ "$(/etc/init.d/rc.inotify_tools status)" == "running" ]; then
/var/tmp/iw_continuous > /dev/null 2>&1 &
fi
Das Skript erzeugt ein weiteres, ausführbares Skript, welches im
Hintergrund gestartet wird und die eigentliche kontinuierliche
Konsolidierung des großen Logs übernimmt. Die konsolidierte Liste der
Dateien wird regelmäßig aktualisiert in /var/iw-unique.log
, wo man sie
jederzeit einsehen kann. Sie sieht in etwa so aus (Ausschnitt):
/
/etc/.subversion
/etc/default.callmonitor/system.cfg
/etc/init.d/rc.bftpd
/etc/init.d/rc.cifsmount
/etc/init.d/rc.crond
/etc/init.d/rc.dropbear
/etc/init.d/rc.inotify_tools
/etc/init.d/rc.mini_fo
/etc/init.d/rc.nfsroot
/etc/init.d/rc.samba
/etc/init.d/rc.swap
/etc/init.d/rc.syslogd
/etc/init.d/rc.telnetd
/etc/init.d/rc.webcfg
/etc/init.d/rc.wol
/etc/static.pkg
/lib/libgcc_s.so.1
/lib/modules/2.6.13.1-ohio/kernel/drivers/char/avalanche_led/
/lib/modules/2.6.13.1-ohio/kernel/drivers/char/avm_event/
/lib/modules/2.6.13.1-ohio/modules/
/usr
/usr/
/usr/lib/callmonitor/applets/rc.callmonitor.sh
Damit steht ein mächtiges und nun im nachhinein auch dokumentiertes Analyse-Werkzeug zur Verfügung, mit dem die Möglichkeiten der “Platzspar-Jünger” sich hoffentlich etwas erweitern werden. Viel Spaß beim Ausprobieren. Geduld, Ihr kommt dahinter, bei mir hat es auch gedauert - leider hatte ich diese Doku aus naheliegenden Gründen nicht. ;-)
Im Forum war der Ursprung dieses Pakets meine Idee und Anfrage dort, aktuell kann über das Paket und diesen Artikel diskutiert werden im neuen Thema Paket Inotify-Tools + Anwendungen