User Friendly
Nutzer stolpern nicht selten über unverständliche Fehlermeldungen, die ihr Computer von sich gibt. Zumindest unter Linux/Unix ist dagegen mittlerweile ein wirkungsvolles Kraut gewachsen: die Bibliothek libexplain.
- Michael Riepe
Dass Unix als wenig benutzerfreundlich gilt, liegt nicht zuletzt an der Art und Weise, wie es Anwender über Fehler und ihre Ursachen im Unklaren lässt. Sogar langjährige Nutzer haben Schwierigkeiten, Aussagen wie „Kann die Datei nicht öffnen“ zu deuten, geschweige denn Abhilfe zu schaffen. Kein Wunder, denn die Meldung wirft mehr Fragen auf, als sie beantwortet: Welche Datei? Und vor allem: Warum nicht?
Experten greifen in solchen Fällen zu Werkzeugen wie strace, ktrace, truss oder dtrace, je nachdem, welches Betriebssystem sie nutzen. Deren Ausgabe enthält zumindest einen Teil der notwendigen Informationen:
open("nichtda", O_RDONLY) = -1 ENOENT (No such file or directory)
etwa verrät Eingeweihten, dass das Programm versucht hat, die nicht existierende Datei nichtda zum Lesen zu öffnen – Fakten, die das Programm auch von sich aus hätte liefern können, wäre der Programmierer nicht zu faul gewesen. Zumindest hätte er Funktionen wie perror oder strerror verwenden können, um die Art des Fehlers in die Meldung einzuflechten – sogar in der Muttersprache des Anwenders, sofern der Umgebungsvariablen wie LANG oder LC_MESSAGES richtig gesetzt hat.
Bordmittel genügen nicht
Doch auch damit ist dem Nutzer nicht immer geholfen. Zum einen sind die Fehlermeldungen des Kernels mehrdeutig, zum anderen muss man wissen, auf welches Argument eines Systemaufrufs sie sich beziehen: Beschwert sich etwa rename(altername, neuername) über ein „ungültiges Argument“ oder eine „ungültige Adresse“, stellt sich die Frage, ob damit altername oder neuername gemeint ist. Die jedoch beantwortet der Kernel grundsätzlich nicht, obwohl er die exakte Fehlerursache natürlich kennt.
Eventuell hilft ein Blick in die Manpage des fehlgeschlagenen Systemaufrufs weiter – sofern sie existiert und in einer für den Nutzer verständlichen Sprache verfasst ist. Selbst wenn der Text in ihrer Muttersprache vorliegt und vernünftig übersetzt ist, dürften weniger versierte Nutzer Schwierigkeiten haben, das typische Unix-Fachchinesisch zu enträtseln, das in erster Linie für Programmierer gedacht ist, die das System in- und auswendig kennen. Die wiederum benötigen keine langen Erklärungen, weshalb ihre Software vermutlich auch selten welche liefert.
Ein anderer Grund dürfte sein, dass der Programmieraufwand erheblich sein kann. Er lässt sich jedoch mit der Bibliothek libexplain des Australiers Peter Miller drastisch reduzieren (libexplain.sourceforge.net). Sie kann für momentan 158 Unix- und Linux-Systemaufrufe sowie 444 ioctl-Kommandos passende Fehlermeldungen erzeugen, die alle wichtigen Informationen enthalten – darunter auch solche, die der Kernel nicht preisgibt. Statt eines lapidaren „permission denied“ etwa meldet die Bibliothek, welche Funktion fehlschlug, mit welchen Argumenten das Programm sie aufgerufen hat, welche Dateien involviert waren, welche Zugriffsrechte die Anwendung besitzt und welche sie besitzen müsste.
Expertenwissen eingebaut
Wer in seiner Software strerror verwendet, um Fehlermeldungen des Kernels auszugeben, kann die Funktionen der Bibliothek leicht einbinden. Zu jedem Systemaufruf, den libexplain versteht, gibt es eine Funktion explain_<aufruf>, die dieselben Argumente erwartet und einen erläuternden Text zurückgibt – momentan nur in englischer Sprache, aber die Infrastruktur für eine „lokalisierte“ Version ist bereits vorhanden. Im Gegensatz zu strerror holt sich die Funktion den Fehlercode direkt aus der (thread-)globalen Variablen errno:
if (chmod(path, mode) == -1) {
fprintf(stderr, "%s\n",
explain_chmod(path, mode));
exit(EXIT_FAILURE);
}
Will oder muss der Programmierer den Fehlercode explizit übergeben, kann er stattdessen explain_errno_chmod(errno, path, mode) verwenden. Die Varianten explain_message_chmod und explain_message_errno_chmod schreiben die Fehlermeldung in einen bereitgestellten Puffer. Sie sind nützlich, wenn das Programm die Fehlermeldung auf andere Weise anzeigen will, etwa in einem eigens dafür geöffneten Fenster auf der grafischen Oberfläche.
Aufrufe von perror(text) kann der Entwickler zumindest im Geiste durch das äquivalente fprintf(stderr, "%s: %s\n", text, strerror(errno)) ersetzen. Für die Faultiere unter den Programmierern – also die große Mehrheit – bietet libexplain außerdem zwei Wrapper-Funktionen an. explain_chmod_or_die(path, mode) etwa ersetzt obigen Fünfzeiler durch einen einzigen Funktionsaufruf. Soll das Programm trotz des Fehlers weiterlaufen oder muss es noch Aufräumarbeiten erledigen, kann man stattdessen explain_chmod_on_error(path, mode) verwenden. Die Funktion ruft chmod auf, gibt gegebenenfalls eine Meldung aus und kehrt anschließend mit dem Rückgabewert von chmod zum aufrufenden Programm zurück.
Beide Funktionen schreiben auf die Standardfehlerausgabe (stderr). Wer ein Programm entwickelt, das im Hintergrund läuft, kann Fehlermeldungen mit der Funktion explain_output_register ohne großen Aufwand auch an syslogd oder in eine beliebige Datei umleiten. Genügt das nicht, kann der Programmierer mit explain_output_new seinen eigenen Output Handler erzeugen.