Unix ist als schwer administrier- und bedienbar verschrien. Als
Ursache wird die hohe Komplexität des Systems genannt. Leider ist das
nur die halbe Wahrheit. Auch Fehler und Unzulänglichkeiten im System
sowie unzweckmäßige Auslegungen von Komponenten des Kernels und von
Systemkommandos tragen in erheblichen Maße dazu bei. Der Artikel zeigt an
Hand von auffälligen Beispielen, was an Unix geändert werden muss, damit
es gegenüber anderen Betriebssystemen (im Desktopbereich) mittelfristig
bestehen kann.
Inhalt
Übersicht Konfiguration von Unix Die Bildschirmansteuerung Eingabe Ausgabe Schlechter Zustand vieler Programme Schlechtes Design des Zusammenspiels von Komponenten Fehlende Einsicht in die Probleme, die Unix-kompatible Betriebssystem haben Weitere Wünsche Lösung der Probleme Systemkonfiguration Konsolenansteuerung Programme/Programmpakete Ideologische Probleme
Ich bin das erste mal mit Unix vor elfeinhalb Jahren in Berührung gekommen, mit Linux vor dreieinhalb Jahren, seitdem nutze ich es für die meisten Probleme als Arbeitsbetriebssystem. Nach über drei Jahren sollte man die meisten auftretenden Probleme ohne großen Zeitaufwand beheben können. Leider ist das nach meinen Beobachtungen selten der Fall. Man stolpert dauernd über Probleme, die sich als ungewöhnlich zeitintensiv herausstellen, die sich prinzipiell nicht sauber oder nur durch Tricks, die mit dem eigentlichen Problem nichts zu tun haben, lösen lassen.
Die sich mir in den Weg stellenden Schwierigkeiten habe ich in den letzten sechs Monaten aufgeschrieben und versucht zu systematisieren. Wie ich feststellte, lassen sich viele davon auf wenige Ursachen zurückführen. Die wichtigsten werden im Folgenden erläutert.
Die Hauptprobleme sind:
Der Schluss des Artikels wird dem Thema gewidmet, wie man prinzipiell zur Lösung solcher Probleme vorzugehen hat.
Die Konfiguration von Unix erfolgt in der Regel durch viele kleine ASCII-Dateien, die im Verzeichnis /etc/ oder personenbezogen im Heimverzeichnis stehen. Leider ist dies nicht die ganze Wahrheit.
Es gibt noch viele andere Stellen, an denen Konfigurationsinformationen abgelegt bzw. eher verborgen sind:
Viele andere Verzeichnisse, z.B. /var/lib/*/, /usr/X11/lib/X11/*, /boot/, /sbin/init.d/, /usr/lib/, /usr/local/lib/ um nur einige zu nennen.
Implizite und eincompilierte Parameter in Programme (schlimm) oder Kernel (sehr schlimm).
Parameter, in Form von Vorhandensein von bestimmten Verzeichnissen mit bestimmmten Rechten.
Konfiguration durch Modifizieren von Teilen des mitgelieferten Programms, weil man das gewünschte nur dort modifizieren kann (jed) oder sie sonst für jede Person einzeln lokal ablegen müsste (joe).
Besonders die eincompilierte Parameter sind hochgradig problematisch. Sie sind häufig nicht einmal dokumentiert, ihr Vorhandensein weniger einem Designprozess als mehr einem in der Vergangenheit schnell zu behebendem Problem zu verdanken.
Desweiteren gibt es folgende Probleme:
Aus dem Programmnamen lässt sich nicht der Name der Konfigurationsdatei(en) ableiten und umgekehrt.
(Not-)Vorschlag:
Die Konfigurationsdatei des Programmes yyy des Paketes xxx heißt /etc/xxx/yyy.conf, weitere Dateien sind in dieser Datei explizit anzugeben und haben in der Hierarchie /etc/xxx/ oder ${HOME}/.private_etc/xxx/ zu liegen.
Kompatiblitätslinks in /etc/ sind in der Anfangszeit erlaubt.
Es gibt zu viele Konfigurationsdateien, die sich nicht orthogonal verhalten, d.h. die Struktur ist unnötig komplex oder - schlimmer - es werden nicht alle Fälle abgedeckt. Konfigurationsdateien haben nicht die für eine freie Konfiguration notwendigen Kompetenzen.
Beispiel:
bash, es gibt viele Konfigurationsdateien (/etc/profile, ~/.bash_profile, ~/.bash_login, ~/.profile, ~/.bashrc, ~/.bash_logout), aber z.B. keine globale Datei für das Logout und für das Login einer Nicht-Login-Shell.
Beispiel:
ksh: Interferenz mit der Konfiguration der bash, da /etc/profile und ~/.profile zwangweise von beiden genutzt werden.
Vorschlag:
Konfigurationsdatei /etc/bash/bash.conf für die bash und /etc/ksh/ksh.conf für die ksh, die vollständig den weiteren Startvorgang steuern.
Weiterhin werden folgende weitere Fehler gemacht:
Konfiguration ist kaum normalisiert, d.h. eine bestimmte Information ist vielfach vorhanden und muss bei Änderungen an vielen Stellen angepasst werden. Nur teilweises Ändern führt häufig zu mit der eigentlichen Ursache schlecht in Zusammenhang zu bringenden Auswirkungen.
Gleiche Dateien werden von verschiedenen Programmen gelesen und unterschiedlich interpretiert (/etc/issue von mingetty und login)
Konfiguration erfolgt bis auf wenige Ausnahmen vollständig programmorientiert, d.h. eine gewünschte Eigenschaft muss für alle Programme getrennt eingestellt werden, z.T. ist dies nicht einmal möglich. Insgesamt sehr aufwendig. Ansätze, dem entgegenzuwirken, gibt es bei den X-Resourcen (dort mit anderen Designfehlern) und bei KDE (nicht näher analysiert).
Es werden Informationen aus verschiedenen Kategorien in einer Konfigurationsdatei gemischt gespeichert. Upgraden oder Übertragen auf andere Systeme wird damit sehr aufwendig und fehleranfällig. Die Mindesteinteilung sollte in
erfolgen. Diese Aufzählung ist nicht vollständig.
Fehlende Orthogonalität der Optionen, zu viele Optionen mit trotzdem dringend notwendigen fehlenden Funktionen.
Nicht dokumentierte Interferenzen zwischen Optionen eines Programmes oder mit Optionen anderer Programme, unnötige Interferenzen zwischen Optionen durch fehlende Orthogonalität.
Die Konfigurationsdateien haben unterschiedlichste Formate, die Formate sind nur verbal beschrieben (ich habe noch nie eine Beschreibung in BNF gesehen), es sind häufig nicht einmal Beispiele angegeben.
Die Parser für die Konfigurationsdateien sind meist lausig geschrieben, Fehlermeldung häufig irreführend oder vollständig fehlend. Auch einfaches Hängenbleiben oder Abbrechen von Programmen ist möglich. Selbst gleich aussehende Konfigurationsparser weisen Unterschiede auf:
Wird Groß- und Kleinschreibung unterschieden, wenn ja, welche Zeichen sind groß- und welche kleinzuschreiben (X-Resourcen)?
Sind Leerzeichen und/oder Tabulatoren erlaubt, oder muss zusammengeschrieben werden? Wo sind sie erlaubt? Darf eingerückt werden?
Sind Leerzeichen am Ende erlaubt?
Wo dürfen Kommentare stehen? Mit welchem Zeichen werden diese eingeleitet? Dürfen diese eingerückt werden? Dürfen diese nach Nutzinhalt stehen oder dürfen sie nur auf separaten Zeilen stehen?
Welche Zeichen haben Sonderfunktionen? Haben sie diese Sonderfunktion nur am Zeilenanfang? Gibt es ein Escapezeichen, wenn ja, wie lautet es?
Wie wird mit fehlerhaften Einträgen umgegangen? Werden diese angezeigt, ignoriert oder wird das Parsing abgebrochen?
Wie lang dürfen Zeilen werden? Welche weiteren Beschränkungen gibt es außerdem? Sind diese notwendig, wenn ja, warum?
Dürfen überlange Zeilen umgebrochen werden? Wie dürfen sie es? Erfolgt das Zeilenzusammenfügen vor oder nach dem Entfernen der Kommentare? Beispiel:
Das ist eine überlange Zeile # und das ein Kommentar \ Ist das hier nun ein Kommentar oder nicht?
Wer garantiert mir, dass sich die nächste Version beim Parsen der Konfiguration exakt so verhält wie die aktuelle, wenn ich Features benutze, die in beiden Versionen vorhanden sind?
In Zusammenhang mit Fehlern in der Dokumentation und fehlenden Fehlermeldungen ist das tatsächliche Verhalten fast nur durch Quellenanalyse feststellbar. Das gilt selbst für Programme mit ansonsten guter Dokumentation.
Nur:
Außerdem ist man dadurch gezwungen, sich an der konkreten Implementierung statt an der Spezifikation bei der Konfiguration zu orientieren. Das ist falsch und fehlerträchtig. Fehler mit strace oder strings zu suchen, ist ein Anzeichen eines wenig transparenten Systems.
Desweiteren treten folgende Probleme auf:
Konfigurationsdateien sind häufig so aufgebaut, dass sie Fehler geradezu provozieren. Die Struktur und die Funktionsweise werden verschleiert, heuristische Automatismen sind erst nach Lesen von langen Dokumentationen erkennbar.
Beispiel: /etc/lilo.conf
Assoziativität der Einträge nicht erkennbar (image, boot, label)
Automatisches Plattenmapping zwischen Unix-Gerät und BIOS-Gerät (/dev/hda ist immer BIOS-Gerät 0x80 (IDE vorhanden vorausgesetzt), es sei denn, man definiert, dass 0x80 0x81 und 0x81 0x80 bedeutet).
Zeitangaben in Nicht-SI-Einheiten.
Falsche Fehlermeldungen bei der Installation: /boot/ auf eigener Partition unterhalb des Zylinder 1024, /etc/boot.messages im Root-Filesystem oberhalb von Zylinder 1024, Meldung: "Root device exceeds 1024 cylinder limit".
Beschreibungsdatei beim Start und Konfigurationsdatei werden unabhängig voneinander abgespeichert.
Lausige Bedienung (kein Stop des Timeouts bei Tastatureingabe, völlig fehlende Benutzerführung)
Unterschiedliche Angabe von Parametern, Nichtbeschreiben dieser in der Dokumentation. Bei der Angabe von Speicherendadresse wären z.B. möglich: 0xD000, 0xCFFF, 0xD0000, 0xCFFFF, 0D000h, D000, D000:0, 0D000h:0, 851968, ...
Häufig ist es wichtig zu wissen, wie die Daten zwischendurch interpretiert werden. So kann manchmal vor Unix-Rechten eine führende 0 notwendig sein, damit die Zahl als Oktalzahl gelesen wird!
Ignorieren von Konfigurationsparametern und Ersetzen durch Standardwerte. (Schon mal den Eintrag für das /proc-Dateisystem durch was anderes ersetzt oder gelöscht?)
Programme können ein Ändern ihrer Konfiguration nur durch Pollen mitbekommen:
Manche pollen in zyklischen Abständen, belasten damit die CPU und lassen auf Laptops die Festplatte nicht ruhen. Desweiteren erfolgen die Änderungen erst nach einer gewissen Zeit, die vom Benutzer nicht erkennbar ist. Selbst unter den pollenden Programmen gibt es welche, die sich über veränderte Konfigurationen beschweren statt sie auszulesen (sendmail).
Manche warten auf ein SIGHUP, woher soll der Anwender aber wissen, wer alles auf diese Weise zu benachrichtigen ist? Es gibt keine Möglichkeit (außer dem Neustart), das zu garantieren.
Manche müssen manuell beendet und neu gestartet werden. cron z.B. streckt nur alle Viere von sich, wenn er ein SIGHUP bekommt.
Auch das Starten bestimmter Scripte oder das Aufrufen verschiedener Programme ist eine weitere Form des Aktivieren von Konfigurationsdateien (/etc/aliases, /etc/fstab, ...).
Meine persönliche Meinung dazu: Das ist Murks in Reinkultur!
Die Konfiguration per Textdateien ist für viele Dinge anstrengend und aufwendig, besonders in Dateien mit aufwendigeren Strukturen (fvwm2rc, fvwm95rc).
Es ist nicht feststellbar, welche Konfigurationsdaten ein Programm ausgelesen hat, welche Konfigurationen durch welche verdeckt wurden, und welche nicht gefunden wurden. Es ist zur Unsitte geworden, viele Stellen des Dateisystems nach möglichen Konfigurationdateien abzusuchen. Das ist langsam, fehleranfällig, unübersichtlich und lernaufwendig. Desweiteren ist nur ein Überschreiben möglich, kein Modifizieren einzelner Eigenschaften.
Ein Rücknehmen von Modifikationen durch das Betriebssystem oder ein Feststellen des Verursachers sind unmöglich.
Lösen ließe sich das Problem zum Beispiel durch ein zentrales Datenbankmanagmentsystem, das die Verwaltung der Systemkonfiguration übernimmt. Dies kommt der Unix-Philosophie entgegen, wo es für alle Aufgaben genau ein Programm gibt, das sich genau auf eine Aufgabe, die es dafür richtig beherrscht, beschäftigt. Dieses eine Programm praktisch fehlerfrei zu bekommen, ist möglich. Bei vielen Programmen ist es praktisch unmöglich.
Realisiert wurde dieses Prinzip u.a. bei AIX und HP-UX.
MS-Windows 9x/NT hat eine Konfigurationsdatenbank. Dabei wurden etliche Fehler gemacht, die einer zentralen Konfigurationsverwaltung einen sehr schlechten Ruf einbrachten:
Keine nutzbaren Zugriffseinschränkungen, jeder Prozess kann diese Datenbank modifizieren. Programme gehen davon aus, dass sie uneingeschränkt die Registry modifizieren können.
Wenig Transparenz (versteckte Parameter, Konfiguration zu verstreut, keine Sortierung nach Programmpaketen).
Kein Notieren der letzten Modifikation und des letzten Modifizierers eines Eintrags, keine Recherchen möglich.
Keine Kategorien, statt dessen einfaches Überschreiben.
Zumüllen der Datenbank durch Hineinschreiben jeder Information, die nichts mit Konfiguration zu tun hat (Spielstände u.ä.).
System hängt auf Gedeih und Verderb von dieser Datenbank ab, da dort elementar wichtige Informationen (Registrierschlüssel) abgespeichert sind, ohne die kein (Anwendungs-)Programm gestartet werden kann.
Die Tastaturschnittstelle stammt aus einer Zeit, in der vor allem mit seriellen Terminals gearbeitet wurde. Cursortasten waren Luxus. Mäuse gab es außer für Spezialanwendungen nicht. Erweiterungen erfolgten (ähnlich wie INT10 unter MS-DOS) von unten nach oben.
Dadurch ergeben sich folgende Probleme:
fehlende Standardisierung. Autoren der Programme haben häufig ein anderes Mapping haben als man selbst. Nach Installation ist erst einmal ein Anpassen dieses an den eigenen Rechner notwendig. Zum Teil geht das nicht einmal, da das Programm diese nicht vorsieht oder sich diese Eigenschaft gerade nicht verstellen lässt. Zum anderen widersprechen sich viele Programme in ihren Anforderungen, d.h. das Mapping müsste programmspezifisch erfolgen.
Wenn man alle Programme mit einer einheitlichen Belegung versehen möchte (nervenschonend, adrenalin-senkend, weniger lernintensiv) und alle Tasten nutzen möchte (z.B. weiße Plustaste und graue Plustaste haben unterschiedliche Funktionen), steht man häufig vor unlösbaren Problemen.
Fehler bei der Dekodierung des Datenstroms, da dieser bei den üblichen Mapping nicht fehlerfrei dekodierbar ist.
Keine Unicode-Unterstützung.
Keine transparente Unterstützung von weiteren HID (Human Interface Devices) wie z.B. mehreren Tastaturen, Mäusen, Graphiktabletts, Barcodeleser, Chipkarten, Identifikationssystem und Autorisierungssysteme über eine (flexible) Schnittstelle (sonst Race Conditions über Netzwerke!).
Fehlende Übertragung von z.B. folgenden Informationen:
Fehlerhafte Behandlung der Modifizierertasten Shift, Alt, Ctrl bei Konsolenwechsel. Fehlerhafte Behandlung beim Umschalten zwischen übersetzten Konsolen und Raw-Konsolen (dosemu, X11).
Schwer zu verstehende, unübersichtliche und fehlerträchtige Schnittstelle, die Programmierer davon abhält, überhaupt Programme zu schreiben oder die von dem sauberen Implementieren der eigentlichen Programmfunktionalität mehr oder weniger ablenkt. Um so etwas überhaupt handhaben zu können, ist man auf Toolkits (z.B. curses) angewiesen. Grundlegende Fehler bleiben trotzdem bestehen. Der Programmcode wird davon außerdem auch nicht schneller und kürzer.
Mehrfachübersetzung von Tastaturcodes durch mehrere Programme und Bibliotheken, Auftreten des "Stille Post-Syndroms".
Hier gibt es folgende Probleme:
Langsam.
Schwer zu verstehende, fehlerträchtige Schnittstelle
Programme verhalten sich unterschiedlich, abhängig davon, ob sie auf der Konsole, in einem xterm oder rxvt oder über NFS laufen.
unmerkliches Verstellen von Parameter über Programme hinaus ist möglich, ohne das man es direkt merkt. Ein grep auf eine Binärdatei führt schnell mal zu Fehlfunktion des darauf gestarteten Editors.
Fehlerhafte Ausgaben, Redraw wird zur wichtigsten Funktion von Applikationen überhaupt. Man kann sich nicht auf die Richtigkeit von Bildschirmausgaben verlassen (so was nennt man Unzuverlässigkeit).
Die meisten Programme existieren seit Jahrzehnten. Sie sind seitdem teilweise von vielen verschiedenen Personen erweitert und modifiziert worden. Zum Teil mit und zum Teil ohne Verständnis des gesamten Programms. Auffällig sind folgende Dinge:
Viele Automatismen, die schlecht dokumentiert sind, und die, wenn man designt hätte, überflüssig wären.
Race Conditions. Besonders Scripte sind darauf angewiesen, dass Programme innerhalb einer gewissen Zeitspanne auch wirklich gestartet worden, "gewährleistet" wird dies durch großzügig bemessene Aufrufe von sleep. Langsam, unsauber, fehleranfällig. Selbst die Standardliteratur für Unixprogrammierer ist betroffen (Stevens)!
Fehlende Abgeschlossenheit der Aufgabe eines Programms, es werden gern mit andere Aufgaben übernommen bis hin zu Bugfixes und Workarounds in anderen! Programmen, z.T. mit nicht absehbaren Nebenwirkungen. Eigene Aufgaben dagegen werden vernachlässigt.
Programme werden nicht aufeinander abgestimmt, sondern mit "heißer Nadel" zusammengestrickt. Nicht vorhergesehene Fälle lassen diese schlecht lokalisierbaren Fehler wieder aufbrechen. Üblich ist dann ein erneutes Work-Around statt den eigentlichen Fehler zu beheben.
Fehlende Konfigurierbarkeit trotz unübersichtlicher Anzahl von Optionen (xterm).
Fehlerhafte oder fehlende Fehlermeldungen, keine verwertbaren Fehlercodes zur Zusammenarbeit mit anderen Programmen. Die dann anzutreffende Analyse der Fehlermeldungen funktioniert bei Änderung der Fehlermeldungen nicht mehr. Keine Beschreibung von Fehlercodes. (mcopy, pgp, mount, dd, mkswap). Unsinnige Fehlercodes, z.B. die Rückgabe von 0 bei schwerwiegenden Fehlern (/sbin/halt).
Aufruf von eincompilierten, externen Programme ohne Test, ob diese im aktuellen Suchpfad vorhanden sind.
Schlimmes Beispiel: /sbin/init
Dieses Programm zeigt in konzentrierter Form viele Todsünden der Programmierung (bitte Quellen durchlesen). Was wird hier in massiver Form durchgeführt? Externe Programme werden hartkodiert aufgerufen, ob vorhanden oder nicht, Fehlermeldungen werden vorsorglich auf /dev/null umgelenkt.
Veraltete Dokumentation, fehlende Dokumentation oder Dokumentation, die die grundlegende Funktionsweise verschweigt. Nichtnennen von verwendeten Dateien und Kommunikationspartnern oder verwandter Komponenten/Funktionen, verbales Beschreiben ("dann müssen sie die Endadresse angeben"). Fehlende Beschreibung von Wechselwirkungen von Optionen, die fast an der gleichen Eigenschaft rumschrauben.
Bemerkung: Eine Dokumentation muss die Blind-Konfiguration eines unbekannten Programms zulassen, sonst ist es keine Dokumentation, sondern bestenfalls eine Ratehilfe.
Fehlende Benutzerführung, die Konfiguration erfolgt ausschließlich durch ein Programm, das von Syntax und Semantik des Programms keine Ahnung hat (Texteditor). Kein Möglichkeiten, die möglichen Konfigurationsparameter eines Programms herauszubekommen (X11 und X-Resourcen).
Fehlende Plausiblitätsüberprüfungen vieler Programme
Beispiel: mwrite Vortrag.html schreibt Vortrag.html nicht auf Diskette, sondern kürzt die Datei auf der Festplatte auf die Länge 0.
Durchsuchen vieler Stellen im Dateisystem nach benötigten Dateien statt Suche an genau einer definierten Stelle. Langsam, unübersichtlich, ob dabei die vom Programmierer/Systemadministrator beabsichtigte Datei gefunden wird, ist zweifelhaft. Kann für Systemangriffe genutzt werden.
Schlechtes bis sehr schlechtes Laufzeitverhalten etlicher Programme (z.B. less).
Keine einheitlicher Syntax.
Keine Kapslung von Funktionalität, zusammengehörige Funktionalität liegt häufig in unterschiedlichen Ebenen. Nach der ersten Implementierung hat sich keiner mehr gefragt, wo eben diese Funktionalität hingehört.
Beispiel: rnews löscht Newspakete, wenn es der Meinung ist, dass nicht mehr genug Speicherplatz vorhanden ist. Woher es diese Information nimmt (1,2 GByte per NFS sind nicht ausreichend, es müssen schon 5 MByte auf der lokalen Platte sein), lässt sich nicht ohne weiteres feststellen. Dieses Verhalten ist weder dokumentiert noch lässt es sich abschalten!
Trostpflaster: Etliche Programme sind sehr gut designt und haben ein sehr gutes Laufzeitverhalten (Beispiel: grep).
Ein großer Teil der Unix-Programme ist über Jahre hinweg von vielen verschiedenen Personen modifiziert und erweitert worden, wenn weitere Aufgaben anstandenn. Oftmals ist nur die anstehende Aufgabe gelöst worden, ohne sich zu fragen, wie man mit einem besseren Konzept alle Aufgaben dieser Art lösen könnte. Auf diese Weise sind zu viele Programme im Umlauf, die sich bei genauer Analyse als Flickenteppich heraustellen. Solange diese Programme nur lose im System verankert sind, kann man sie wegwerfen und vollständig neu programmieren. Leider geht das häufig nicht, weil eben diese Programme mit genauso verhunzten Programmen zusammenarbeiten, die ein sauberes Design verhindern. Andere Fehler haben sich als Standard etabliert oder sind fest im Kernel verankert.
Keine saubere Unterstützung von Wechselmedien und NFS-Laufwerken, diese werden wie feste Medien angesprochen. Es ist manchmal sogar kein umount nicht mehr existierender NFS-Partitionen möglich. In diesem Fall ist die Lösung für ein Festmedien, weil sie schon vorhanden war, für etwas verwendet worden, wofür sie ungeeignet ist. Noch schlimmer ist es, dass so was mittlerweile als selbstverständlich angesehen wird.
Die Scriptsprache der bash ist fehleranfällig und kompliziert, obwohl es keine vollständige Programmiersprache ist. Ein Syntaxcheck von Scripten ist nicht möglich, da dessen Korrektheit von externen Einstellungen abhängt.
Fehlendes Locking von Dateien durch das Betriebssystems, Es muss zumindest der (wahlfreie) Schreibzugriff von mehreren Programmen auf eine Datei zuverlässig unterbunden werden. Stehengebliebene "Lock"-Dateien führen zu völligem Versagen von Systemdiensten.
Beispiel: cnews, gpm
Häufig werden Probleme statt Ursachen gelöst:
Beispiel: Init-Prozess
Damit Dämonen, die von einer Shell (Bug!) gestartet werden, bei deren Beendigung nicht gekillt werden, lösen sich diese vom startenden Programm durch Prozessgruppenwechsel (setpgid()), Sessionwechsel (setsid()) und fork()-Orgien. init kann dadurch nicht feststellen, ob ein Dämon überhaupt ordnungsgemäß gestartet wurde, oder ob er noch läuft. Korrigiert wird dies durch weitere Prozesse, die in der Prozesstabelle nachsehen, ob ein Prozess mit dem "richtigen" Namen noch vorhanden ist. Das ist Heuristik statt Determinismus. Nur der Elternprozess kennt exakt die PID des Kindprozesses bzw. kann über das Ableben eines Kindsprozesses benachrichtigt werden. Deswegen hat genau dieser Prozess (Programm ist nicht ausreichend) sich darum zu kümmern. Ob Programme laufen, wird häufig dadurch getestet, ob ein Programm mit einem bestimmten Basisnamen läuft. Was ist, wenn normale Benutzer für Programme Namen wie gpm oder pppd verwenden?
Neben den programmtechnischen Problemen von Unix gibt es noch die folgenden:
Fehlende Einsicht, dass Unix nicht das Nonplusultra ist, dass Etliches überdacht, neu konzipiert und sogar neu programmiert werden muss, um immer wieder auftauchende Probleme sauber (das heißt leider nicht für immer!) aus dem Weg zu räumen. Statt dessen wird immer wieder an falschen Konzepten rumgepatcht, die das ganze aufwendig, unübersichtlich und fehleranfällig machen.
Hegemonie und Überheblichkeit, statt Probleme zu analysieren und mittelfristig zu beheben, werden Designfehler als Features oder das Nonplusultra hingestellt. Anfragen in Newsgruppen werden häufig unhöflich mit Verweis auf (schlecht verständliche, unzureichende und fehlerhafte) Dokumentation beantwortet, statt kurz eine Hilfestellung zu geben oder das Programm so zu gestalten, dass dieses Problem nicht mehr auftaucht.
Gute Konzepte anderer Betriebssysteme sollten, wenn nicht patentiert, überhaupt zur Kenntnis genommen werden und - gegebenfalls weiter optimiert - übernommen werden. Statt dessen werden diese pauschal verdammt.
/dev ähnlich wie /proc als Pseudo-Dateisystem für alle (ohne Ausnahme, d.h. auch Geräte wie /dev/eth0) aktuell im Kernel verfügbaren Geräte (Major und Minor-Nummern sind dann uninteressant, /dev/null kann nicht mehr zur Datei mutieren).
Beachte:
Verschwinden von Kernel-Statusdateien (/etc/mtab, /etc/mdtab, /etc/rmtab etc.) aus dem regulären Dateisystem. Statusinformation sind vom Kernel abzufragen. Alles andere ist für exakte Diagnostik wertlos.
Bemerkung: Zusammen mit einem virtualisierten /dev ist dann ein Read-only-Root-Dateisystem möglich! Nur noch /var und /home sind dann Read/Write gemountet.
Soft mantatory locking: Kein Erlauben von Mehrfachzugriffen auf Dateien, die meist/garantiert zu Datenverlusten führen, z.B. zweimal wahlfreier Schreibzugriff auf eine Datei.
Moderneres Dateisystem:
Trigger auf Dateien und Verzeichnisse (verhindert das vielfach verwendete Pollen von Dateien), notwendig für stromsparenden Laptopbetrieb.
Unterstützung von Wechselmedien, ein Unmount sollte auch bei genutzten Resourcen des Mediums möglich sein (medienweise konfigurierbar, da es verschiedene Möglichkeiten der Reaktion gibt).
Beispiel: Aktuelles Verzeichnis eines Prozesses ist auf dem Medium, damit keine relativen Pfade mehr möglich.
Wenn man ein (aufwendigeres technisches) Produkt zu entwerfen oder eine (aufwendigere technische) Aufgabe oder Problem zu lösen hat, mit dem man sich schon länger beschäftigt hat, und bei dem Qualität im Vordergrund steht, dann sind folgende Dinge nicht zu machen:
Sondern es ist folgendermaßen vorzugehen:
Es sind alle gewünschten (nach außen sichtbaren) Eigenschaften und alle unerwünschten (nach außen sichtbaren) Eigenschaften in verschiedenen Kategorien (unbedingt notwendig, dringend gewünscht, gewünscht, gern mitgenommen) zu sammeln und in weitem Kreise zu diskutieren. Die Analyse schon bekannter Lösungen mit all ihren Fehlern sind i.A. sehr hilfreich. Die Lebensdauer des Produktes ist dabei zu berücksichtigen (möglich: von einem Jahr bis zwanzig bis dreißig Jahre).
Manche nennen so etwas auch Lastenheft. Es ist allerdings kein Lastenheft, da es allgemeiner ist und mehr dem prinziellen Finden einer Lösung dienen soll.
Es ist zu analysieren, ob es nicht schon Produkte gibt, die diese geforderten Eigenschaften weitgehend erfüllen. Ist das der Fall, kann man hier aufhören.
Erst dann kann man anfangen, sich Gedanken über konkret mögliche Implementierungen und Schnittstellen zu machen. Dabei sind dann solche Dinge zu klären, welche Eigenschaften niedriger Kategorien aus dem Lastenheft entfernt werden, weil das Problem durch sie nicht lösbar oder viel zu komplex wird. Mathematische Exaktheit sollte hier selbstverständlich sein, um möglichst viele Probleme im Vorfeld zu klären.
Beachte: Ein Problem ist nicht dann nicht lösbar, wenn einem in fünf Minuten keine Lösung einfällt. Ein Problem ist nicht dann lösbar, wenn einem sofort eine Idee kommt, wie man es lösen könnte!
Die Schnittstellen sind in weitem Kreise zu diskutieren. Diese sind es, mit denen sich die nächsten Generationen rumzuärgern haben. Alternative interne Implementierungen sind jederzeit möglich, bei Schnittstellen ist das unmöglich!
Bemerkung: Für die Phasen (3) und (4) ist eine Testimplementation erforderlich. Nur durch eine solche ist es möglich, sich später nicht mit unpraktischen Schnittstellen rumzuschlagen, da man merkt, wo es Probleme gibt. Eine leicht geänderte Schnittstelle kann ohne Leistungsverlust das Programm erheblich vereinfachen. An diese Testimplementation wird keine Forderung gestellt, außer dass sie geht, d.h.:
Diese Testimplementation ist nach Erstellung des Lastenheftes irreversibel wegzuwerfen. Das Nutzen von leistungsfähigen Tools ist erwünscht (z.B. yacc, lex)
Aufstellen einer Präambel, was das Programm macht (drei bis fünf Sätze). Exakte Spezifikation des Lastenhefts (dies ist das Wertvollste an diesem gesamten Vorgehen).
Dann haben Hand in Hand nach Lastenheft (z.B. auch von einer ganz anderen Person) zu erfolgen:
Dokumentation - Implementation - Test
Bemerkung: Die Programmierung von Tools hat nach deren Dokumentation zu erfolgen. Nur dann erhalte ich eine relativ kurze, richtige und konsistente Dokumentation. Andernfalls ist die Dokumentation häufig nur der verzweifelte Versuch, die Syntax des vor Monaten programmierten nachträglich zu rechtfertigen. Fehler sind im Programm abzuändern, nicht in der Dokumentation.
Nachteil ist, dass das Ganze etwas länger dauert, dass es (am Anfang) deutlich mehr Aufwand bereitet, dass die Hemmschwelle viel höher ist, so mit einer Aufgabe anzufangen. Desweiteren steht es mit den Grundprinzip von Unix (Schneller Entwurf eines Prototypen) im scheinbaren Widerspruch. Beide Wege haben ihre Daseinsberechtigung. Einige Kriterien für beide Methoden sind:
Schneller Prototyp:
Aufwendiges Design:
Was heißt das für die oben genannten Probleme?
Ich gebe keine Lösungen an.
Ich gebe nur den Weg an, wie man Lösungen suchen kann.
Da sich die geforderten Eigenschaften langsam ändern und auch bei breit angelegten Diskussionen immer noch etwas subjektiv geprägt sind, wird man die Lösung nicht finden. Bleibt man aber stehen, wird man sich immer weiter von ihr entfernen.
Da sich die geforderten Eigenschaften wie auch die zur Verfügung stehenden Mittel langsam ändern, ist manchmal eine Überarbeitung ganzer Programm(pakete) erforderlich. Eine ehemals perfekt nach Lastenheft designte Lösung kann nach zwanzig Jahren zu einem nicht mehr zeitgemäßen Quick&Dirty-Hack mutiert sein. Stichwort: Zäsur.
Trostpflaster: Saubere Konzepte lassen sich erfahrungsgemäß wesentlich einfacher implementieren. Die Programme werden kürzer, schneller und leistungsfähiger. Es entfällt das dauernde Aufbohren mit Features, die urplötzlich als Wünsche aus allen Richtung auftauchen. Die Dokumentation wird kürzer und verständlicher.
Anschließend nur einige Kurzbemerkungen:
Die Entwicklung wird in die Richtung gehen, dass man sich weiter vom physischen Medium entfernt.
Die elementarsten Konfigurationsinformationen sind roh auf dem Medium abgelegt (Partitionstabelle, Bootlader).
Weitere wichtige Informationen sind eine Ebene höher untergebracht, im Dateisystem (/etc/fstab bzw. /etc/mount.conf, /etc/inittab bzw. /etc/init.conf, /etc/lilo.conf).
Bemerkung: Üblich, seit Dateisysteme üblich geworden sind.
Nicht zum Systemstart notwendige Information wird in eine weiter oben liegende Abstraktionsebene (Datenbankserver) übergehen.
Bemerkung: Üblich, seit Datenbanken üblich geworden sind.
Zur weiteren Entwicklung empfehle ich Doc Emmett L. Brown zu fragen
Moderne, ereignisgesteuerte Eingabeschnittstelle, die mir pro Eingabe durch HIDs (Human Interface Device) eine definierte Struktur mit allen Informationen übergibt, kein Dekodieren von Bit- und Byteströmen.
Unterstützung von vielen verschiedenen Eingabegeräten (Tastaturen, Mäuse, Joysticks, Barcodeleser, Graphiktabletts, usw.) über eine Schnittstelle (damit keine Fehler durch unterschiedliche Laufzeiten der einzelnen Datenströme über Netzwerke).
Übertragung von
in orthogonaler Form.
Schaffung eines Standards mit sehr guter Erweiterbarkeit, dabei keine Fehler auf der Applikationsebene bei unbekannten Erweiterungen (unbekannte Tasten liefern einfach keine Codes).
Unabhängigkeit der einzelnen Systemrufe, d.h. keine unnötigen Wechselwirkungen zwischen früheren Ausgaben.
Kompatiblität durch eine Hintergrundprogramm, welches eine Schnittstelle der alten Art zur Verfügung stellt.
Mut zum Wegwerfen und Neuimplementieren, wenn man den Überblick verloren hat oder keine saubere und wasserdichte Implementierung mehr möglich ist. Man tut sonst sich und anderen keinen Gefallen.
Wegkommen von den 99,9% fehlerfrei arbeitenden Programmen. Auch wenn das die gängige Philosophie ist ("What the hell is the point of throwing away something that works 99.9% of the time...", Linus Torvalds), ein solcher Fehler macht ein System nicht mehr deterministisch, viele davon führen zu einem System, das nur noch von damit vertrauten bedient werden kann, das aber keinesfalls mehr ein elitäres System darstellt.
Beachte: Ein Herzschrittmacher mit einer Zuverlässigkeit von 99,99% steht 52 Minuten im Jahr still.
Außerdem verführt es zum Erstellen weiterer fehlerhafter Programme, zum einen, weil es dann üblich ist darüber hinwegzusehen, zum anderen, weil die Fehlerursache nicht mehr lokalisierbar ist. Ist es mein Bug oder die Auswirkungen eines fremden Bugs?
Nur eine Bemerkung zum Schluss: Die Lösung ökonomischer Fragen mit ideologischen Antworten ist ein schon mehrfach gescheitertes Modell. Das sollte man beim Entwurf immer im Gedächtnis behalten. Es kommt nicht darauf an, eine andere Lösung wie andere zu finden, sondern eine möglichst optimale Lösung.