Die ausführliche Geschichte gab es ja nun schon, hier sind noch einmal die wichtigsten Punkte die bei der Entstehung von Linux beitrugen:
Alles dies zusammen stellte die Plattform für den Aufstieg von Linux bereit. Hinzu kommt natürlich auch das allgemeine Interesse die Entstehung eines Betriebssystems mitzuverfolgen.
Wobei hier klar gesagt werden muß: Linux ist nur der Kernel.
Daher kommen auch zu Recht die Äußerungen von RMS, dass das Betriebs- system eigentlich GNU/Linux heißen müßte. Linus lehnte es für den Kernel ab, da er den Namen unansehnlich fand.
Die ersten Versionen des Kernels erschienen nicht unter der GPL, diese hatten eine linuseigene Lizenz. Diese hatte aber ihre Probleme, so dass eine andere Lizenz ratsam wurde. Da der Kernel aber vom GCC lebt hat sich Linus dazu entschieden die GPL zu verwenden. Dies war nicht, weil er so hinter der Ideologie von GNU stand. Linus war nur wichtig, dass es eine freie Lizenz ist, das ist wohl eine Folge des Minix-Problems.
Dadurch, dass Linux eigentlich nur der Kernel ist, war die Basis für die vielen verschiedenen Distributionen geschaffen. Das dürften die meisten vermutlich eher als einen Nachteil ansehen.
Das Herz eines jeden Betriebssystems ist der Kernel. Dieser umschließt gewissermaßen die gesamten Ressourcen, insbesondere die Hardware. Daher stammt der Name, er schottet das Innerste von den Benutzern ab.
Um den Kernel herum befindet sich die Schale: Shell.
Jeder Benutzer interagiert mit der Shell, die Shell wiederum mit dem Kernel, der wiederum die Hardware ansteuert. So hat weder ein Benutzer noch ein Programm (außer dem Kernel) direkten Zugriff auf die Hardware. Dies ist die Voraussetzung dafü, dass mehrere Programme (Benutzer) parallel arbeiten können ohne sich gegenseitig zu stören.
Es gibt natürlich auch die Möglichkeit, dass Programme direkt mit dem Kernel kommunizieren. Aber für die Sichtweise und Namensgebung ist es nicht unwichtig obiges zu wissen. Die Shell ist schließlich auch nichts anderes als ein Programm.
Programme die nicht innerhalb einer Shell laufen werden gewöhnlich Daemon genannt, Disk and execution monitor.
Laut dem Hacker's Dictionary war die ursprüngliche Bezeichnung wohl doch eher aus dem Reich der Mythologie und wurde dann später als dieses Akronym verkauft. Wichtig ist: Daemonen sind Programme die im Hintergrund laufen und irgendwelche Dinge verrichten. Bei Windows heißen diese Services, ein vergleichsweise profaner Name.
Die Grundaussage ist recht einfach
Alles ist eine Datei
Einen entgegengesetzten Ansatz verwendet Microsoft, hier ist alles geräteorientiert. Es gibt z.B. verschiedene Laufwerke die explizit benannt werden müssen (A:, B:, C:,...), Drucker (LPT:), etc.
Unter Unix sind dies alles Dateien, so heißt die erste Partition einer IDE Festplatte (Master am 1. IDE-Bus) /dev/hda1, der erste Drucker heißt /dev/lp0.
Selbst Netzwerkverbindungen lassen sich via Dateidescriptoren abbilden, d.h. die Routinen für das Lesen aus einer Datei sind die gleichen wie für das Lesen aus einer Netzwerkverbindung. Das macht das Programmieren sehr leicht, allerdings nur auf Benutzerseite, die Kernelseite ist da etwas schwieriger.
Das Alles ist eine Datei stimmt auch nicht in allen Beziehungen, dies trifft eher auf Plan-9 von den Bell-Labs zu. Das sollte einmal der Nachfolger von Unix werden: http://www.cs.bell-labs.com/plan9dist/ Hier werden dann auch Ressourcen auf anderen Computern wie eine Datei behandelt.
Eine spezifischere Beschreibung der Unix-Philosophie ist die von Doug McIlroy, dem Erfinder der Pipe:
Also:
Ein Programm für jede Aufgabe und keine Monsteranwendungen. Das ergibt viele kleine, schlanke und effiziente Programme die zudem leicht zu debuggen sind da sie weniger komplex sind.
Die Programme sollen in der Lage sein zusammenarbeiten zu können, das führt dann zu einem Modulbaukasten.
Als Kommunikationssprache soll Text verwendet werden. Der kann von jedem gelesen werden und er erleichtert die Fehlersuche sehr, es müssen keine binären Standards interpretiert werden. Wenn die Zusammenarbeit zweier Programme schief läuft kann leicht die Zwischenausgabe analysiert werden wodurch Fehler eventuell schneller lokalisiert werden können.
Das ist ein sehr elegantes Prinzip. Durch die Modularität und klaren Grenzen zwischen den Programmen können Fehler wunderbar gesucht und beseitigt werden.
Bei Monsterapplikationen wie z.B. Office-Lösungen ist das nicht so einfach. Entsprechend häufig werden Artikel gefunden die beschreiben wie deren Fehler elegant umschifft werden.
Es ist auch irgendwie verständlich: Ab einer gewissen Komplexität ist das Wissen darüber welche Routine für was zuständig ist und zu welchen Nebenwirkungen Änderungen daran führen können nicht mehr vorhanden oder leicht ableitbar. Viel Eleganter sind da klare Schnittstellen.
Wenn dann auch noch ASCII-Text verwendet wird, ist jeder in der Lage direkt zu sehen wo es klemmen könnte, selbst bei derart komplexen Strukturen wie z.B. XML, auch wenn die Analyse dann ein wenig länger dauert. Wenn das ganze binär wäre, dann müsste für die Fehlersuche das Binäre in Text umgewandelt werden, dann kann aber auch der Fehler in der Umwandlungsroutine liegen!
Oder wenn der Standard in einer Applikation erweitert wird, die zweite die neuen Strukturen noch nicht kennt, dann könnte diese Applikation z.B. einfach sagen:
unsupported directive newimage
Schon kann auf Anhieb festgestellt werden wo der Fehler liegt. In diesem Fall war es ein Programm, dass die MagicPoint-Folien in HTML umwandeln soll. Diese Routine kennt aber newimage noch nicht. Klar, der Name deutet es an, es ist eine neue Methode um Bilder eleganter einzubinden. Hier war es das HW->Kernel->Shell->User Bild aus dem Vortrag.
Dieses Prinzip liegt auch den meisten Konfigurationsdateien zugrunde. Microsoft hat soetwas früher auch verwendet, da waren es die sogenannten INI-Dateien.
Wo soll der Vorteil liegen, wenn diese Konfigurationsdatei derart kryptisch ist, dass ein spezieller Editor verwendet werden muß?
Angeblich soll binär performanter sein. Aber stimmt das auch, wenn alle Konfigurationen in einer Datei liegen anstatt pro Programm eine eigene Datei? Wie oft wird eine Konfigurationsdatei gelesen? Eigentlich doch nur einmal beim Programmstart, da machen die Millisekunden zum Parsen der Datei nicht wirklich etwas aus insbesondere wenn jedes Programm seine eigene Konfigurationsdatei hat.
Der Kernel stellt die Schnittstelle zwischen den Programmen und den Ressourcen/Hardware dar. Keine Anwendung darf direkt auf die Hardware zugreifen. Es wäre auch etwas chaotisch wenn dies möglich wäre, ganz abgesehen von der Sicherheit.
Da Anwendungen aber durchaus mit der Hardware arbeiten müssen gibt es entsprechende Schnittstellen zum Kernel, diese werden Systemaufrufe bzw. System Calls genannt. Sie stehen im Abschnitt 2 der Handbuchseiten.
Die Anwendung teilt z.B. dem Kernel mit welchen Bereich einer Datei sie haben möchte, z.B. Dateinamen und wieviel Bytes. Der Kernel sucht dann die Stelle auf der Festplatte, liest den oder die entsprechenden Blöcke ein und liefert die Daten an die Anwendung zurück. Wo die Datei physikalisch auf der Festplatte liegt braucht die Anwendung nicht wissen.
Der nächste wichtige Punkt ist das Prozessmanagement, das heißt, das Erstellen von Prozessen und deren Überwachung wird auch vom Kernel gesteuert. Dazu zählt das Scheduling, d.h. die Zeiten wann ein Programm wie lange laufen darf.
Multitasking heißt zwar, dass die Prozesse parallel laufen sollen aber in der Realität laufen sie gewöhnlich nacheinander, jeder Prozess bekommt dann kurz die CPU um seine Aufgaben zu erledigen. Nach einer vom Kernel bestimmten Zeit wird der Prozess angehalten und der nächste kommt an die Reihe. Dieser Vorgang wird Scheduling genannt.
Ferner obliegt dem Kernel die Handhabung des Speichers. Dieser zählt nur zum Teil zur Hardware, jeder Prozess bekommt seinen eigenen virtuellen Speicher. Die Abbildung dieses Speichers auf die RAM- Bausteine übernimmt wiederum der Kernel.
Zusammen mit dem Swapspeicher, d.h. der Auslagerung des aktuellen Speicherinhaltes auf die Festplatte, Microsoft nennt es temporäre Auslagerungsdatei, kann so deutlich mehr Speicher adressiert werden als der Computer an Hauptspeicher besitzt.
Genaugenommen braucht nicht jeder Prozess den gesamten Speicher den er anfordert. Aber das ist eine andere Geschichte...
Last but not Least: Der Kernel handhabt auch das Netzwerk sowie die vielen Protokolle wie z.B. TCP oder UDP. Der Kernel stellt zwar verschiedene Schnittstellen bereit, so dass auch Applikationen die höheren Protokolle auswerten können aber in der Regel wird dies dem Kernel überlassen.
Ausnahmen sind z.B. ping und traceroute und natürlich die Tools zum Fälschen von Adressen...
Das meiste bezieht sich hier auf die bash, der Standardshell unter Linux.
Es gibt eine Vielzahl von Shells, was hauptsächlich daran liegt, dass sie die Schnittstelle zum Anwender darstellen, daher auch der Name Shell.
Die Fähigkeiten der ersten Shells waren sehr bescheiden von daher gab es immer Bestrebungen etwas besseres zu erstellen. Auf der anderen Seite musste die Kompatibilität mit der alten Shell erhalten bleiben.
Diese alte Shell ist die Bourne-Shell und befindet sich immer unter /bin/sh.
(Bei Solaris liegt sie unter /usr/bin/sh aber es gibt einen symbolischen Link von /bin/sh dahin. Wer nun im Vorgriff fragt warum die Shell in einem Verzeichnis liegt, dass auf einer anderen Partition als der Root-Partition liegen darf: Der Superuser hat als Loginshell /sbin/sh, das ist eine statisch gelinkte Shell in der Root-Partition.)
Die meistverwendete Shell ist heutzutage die bash, bourne again shell in Anspielung auf den Klassiker unter der sprachlichen Bedeutung von born - geboren, es ist also eine wiedergeborene Shell...
Andere bekannte Shells sind:
Jetzt beschränke ich mich auf die bash als Shell, einige Dinge wie z.B. einen Prozess anhalten und in den Hintergrund verschieben können nicht alle Shells, insbesondere die klassische Bourne Shell kann dies nicht.
Aufgaben der Shell:
Das Starten ist leicht, einfach ein Programmnamen eintippen und Enter drücken. Das Stoppen ist genausoleicht: ^C (STRG-C) drücken, das sendet dem Programm das Signal SIGINT, einen Interrupt also. Dies ist aber nur notwendig, wenn das Programm keine "normale" Prozedur für das Beenden hat.
Programme können mit ^Z (SIGSTOP) angehalten werden. In den Hintergrund geschoben wird es mit dem Kommando bg (background) und fg (foreground) holt es wieder in den Vordergrund.
#! /bin/sh echo "Dies ist ein Shellskript"
Werden diese 3 Zeilen in einer Datei "testscript" abgespeichert und wird ein "chmod a+x testscript" ausgeführt, so kann das Programm auch tatsächlich innerhalb einer Shell gestartet werden. Dazu muss; bei den meisten Distributionen der Pfad mit angegeben werden. Das Einfachste besteht darin "./testscript" zu verwenden. Die Zeichen "./" bewirken, dass nach der Datei im aktuellen Verzeichnis gesucht wird. echo gibt nur wieder was dahinter steht. Die Datei kann aber direkt mit der Shell aufgerufen werden " sh testscript ". Hier zeigt sich der Vorteil, dass die erste Zeile mit einem Kommentarzeichen beginnt: Diese Zeile wird dann einfach ignoriert.
Aber es gibt noch Kontrollstrukturen wie if-then, while-do, for-in-do, etc.
Ein einfaches wiedergeben der Dateien im aktuellen Verzeichnis geht mit:
for i in * do echo $i done
Der Stern * expandiert zu allem was im aktuellen Verzeichnis steht.
Eine Besonderheit gibt es noch: Bei der Zuweisung von Variablen wird kein $-Zeichen verwendet, bei der Referenzierung schon!
Obiges kann auch in eine Zeile geschrieben werden. Dann muß aber jeder Befehl durch ein Semikolon getrennt werden:
for i in *; do echo $i; done
Das kann natürlich direkt auf der Kommandozeile ausgeführt werden
Relevant werden die Programmierfähigkeiten der Shell bei den Shellskripten. Diese sind besonders wichtig in Form der Startskripte beim Booten.
Die Shell kennt auch Umgebungsvariablen (Environment), das sind einfach nur gesetzte Variablen, diese werden aber von bestimmten Programmen gesondert ausgewertet. Die Shell selber nutzt diese ebenfalls, z.B. setzt PATH den Suchpfad für Programme. Diese Variable enthält eine Liste von Verzeichnissen die durch einen Doppelpunkt getrennt sind.
Soll z.B. der Suchpfad um das jeweils aktuelle Verzeichnis erweitert werden, so geht dies mit
PATH=$PATH:.
Allerdings gilt dies nur für Programme die direkt aus der aktuellen Shell gestartet werden. Wird einfach eine neue Shell durch Aufruf von bash gestartet, so ist der alte Wert wieder vorhanden, z.B:
geschke$ echo $TEST geschke$ TEST=true geschke$ echo $TEST true geschke$ bash geschke$ echo $TEST geschke$
Soll TEST auch in Unterprogrammen gesetzt sein, so muß diese Variable exportiert werden:
geschke$ echo $TEST true geschke$ export $TEST geschke$ bash geschke$ echo $TEST true geschke$
Bei der bash kann dies auch alles in eine Zeile geschrieben werden:
geschke$ export TEST=true
< : lesen aus einer Datei > : Schreiben in eine Datei, es wird eine alte gelöscht. >>: Anhängen an eine existierende Datei | : Pipe, die Ausgabe des 1. Programms ist die Eingabe des 2. 2>: Die Fehlermeldungen werden in eine Datei umgelenkt 2>&1: Die Fehlermeldungen werden mit der normalen Ausgabe zusammengelegt
Z.B.:
ls -l | less
Dieser Befehl listet die Dateien im aktuellen Verzeichnis im Langformat (-l) auf und die Ausgabe wird in das Programm less geschrieben. less ist ein sogenannter Pager, d.h. es kann mit ihm seitenweise die Ausgabe angeschaut werden, ansonsten würde alles auf dem Bildschirm ausgegeben.
ls -l > Listing
Dies schreibt obige Ausgabe in die Datei Listing. Diese könnte dann mit less Listing ebenfalls angesehen werden. Hier wird der Vorteil der Pipe offensichtlich, es können ein Zwischenschritt und eine Datei gespart werden.
less < Listing
zeigt natürlich auch den Inhalt von Listing im Pager an.
ls -l >> Listing
hängt die Ausgabe von ls an die Datei an, es ist dann alles doppelt in der Datei.
Mit 2> können explizit die Fehlermeldungen in eine Datei umgelenkt werden, 1> ist der default: die Standardausgabe. Die Funktionsweise der folgenden Zeile ist dann wohl offensichtlich:
/usr/bin/Programm > Programm.out 2> Programm.err
Es besteht nun auch die Möglichkeit die beiden "Kanäle" zu bündeln:
/usr/bin/Programm > Programm.outerr 2>&1
Jetzt werden die Fehlermeldungen in die gleiche Datei umgelenkt wie die normale Ausgabe. Wichtig ist hierbei die Reihenfolge! Diese Zeile hier macht etwas anderes als die Vermutung nahelegt:
/usr/bin/Programm 2>&1 > Programm.out
Jetzt werden die Fehlermeldungen auf die normale Ausgabe umgelenkt. Das ist in diesem Fall der Bildschirm! Die normale Ausgabe wird aber anschließend in eine Datei umgelenkt. Das kann hilfreich sein, wenn z.B. nur die Fehlermeldungen via Pipe weiterverarbeitet werden sollen, z.B.:
/usr/bin/Programm 2>&1 > Programm.out | less
Aliase funktionieren wie es der Name vermuten läßt:
alias la='ls -la'
Schon gibt es das Kommando la welches nichts anders macht als ein ls -la auszuführen.
Mit Aliasen können auch Befehle "überschrieben" werden:
alias ls='ls --color=auto'
Dies bewirkt, dass bei einem ls alles entsprechend des Dateityps eingefärbt wird.
Mit
unalias ls
wird dieser Alias wieder gelöscht, ein nacktes alias, d.h. ohne Argumenten, listet alle gesetzten Aliase auf.
Funktionen sind ebenfalls leicht zu erstellen, z.B.:
listDG() { ls $1; }
$1 ist dabei das erste Argument der Funktion.
Hier wird auch die Funktionsweise der Hochkommata ersichtlich:
majestix:~$ listDG h* highlight-2.2-1.tar.bz2 majestix:~$ listDG "h*" highlight-2.2-1.tar.bz2 honeyd-man.pdf htop-0.3.2.tar.gz
Im ersten Fall expandiert die Shell das h* zu
listDG highlight-2.2-1.tar.bz2 honeyd-man.pdf htop-0.3.2.tar.gz
In dem Fall ist dann $1 = highlight-2.2-1.tar.bz2, also das erste Argument.
Bei listDG "h*" wird der Stern nicht von der Shell expandiert, d.h. $1 = "h*" bleibt und nun listet die Funktion alle Dateien auf die mit h beginnen.
Der Unterschied zwischen dem einfachen (') und dem doppelten (") Hochkomma bezieht sich auf die Auswertung von Variablen. Das wird an einem Beispiel am deutlichsten:
majestix:~$ TEST=true majestix:~$ echo "$TEST" true majestix:~$ echo '$TEST' $TEST
In einfachen Hochkommata werden die Variablen nicht ersetzt.
Der letzte Punkt sind builtins, dies sind eingebaute Funkionen in der Shell. Sie haben zum Teil die gleichen Namen wie Programme, z.B. pwd:
majestix:~$ ln -s /tmp majestix:~$ cd tmp majestix:~/tmp$ pwd /home/geschke/tmp majestix:~/tmp$ /bin/pwd /tmp
Es fällt auf, dass mit dem Pfad aufgerufene Programme just diese sind, keine builtins.
Ein builtin heißt übrigens test, daher sollte nach Möglichkeit ein selbstgeschriebenes Programm nicht test genannt werden, sonst kann oft vergeblich danach gesucht werden warum es nicht so läuft, wie es erwartet wird wenn es mit dem Pfad aufgerufen wurde.
Der Aufbau hat eine Baumstruktur woher sich auch die Bezeichnung root als Anfang ergibt. Verzeichnisse werden durch Slashes "/" getrennt, das oberste Verzeichnis ist nur ein Slash "/" und heißt root-Verzeichnis.
Dies ist das erste Verzeichnis, das beim Booten gemounted ("montiert") wird. Bei Modulen gibt es noch initrd, die initial ram disk die ein Bestandteil des Kernels ist und Module enthalten kann die für das Mounten des root-Verzeichnisses notwendig sind. Dies wird in diesem Fall zuerst gemounted. Das ist aber ein Sonderfall und nicht unbedingt notwendig.
Andere Laufwerke oder Partitionen können einfach in das System ein- gehängt (gemounted) werden. Dazu kann jedes Verzeichnis als Einhängepunkt (Mount-Point) verwendet werden. Einige Verzeichnisse müssen aber auf der root-Partition liegen!
Diese sind im Folgenden mit (r) gekennzeichnet:
/bin (r): (eigentlich) statisch gelinkte Userprogramme /boot: Bootdateien, Kernel /dev (r): Devices, Schnittstellen zur Hardware /etc (r): die Konfigurationsdateien liegen meistens hier /home: Benutzerverzeichnisse /initrd: Inital ram disk /lib(r): Kernel-Module /lib/modules/{kernel.version}/..., Bibliotheken die beim booten benötigt werden für /bin, /sbin /mnt: temporärer Mount-Point, normalerweise ein leeres Verzeichnis /opt: optionale Software /proc: Informationen über Prozesse /root: Homeverzeichnis des Systemadministrators root /sbin(r): (eigentlich) statisch gelinkte Programme für root /sys: Kernel-Informationen, sysctl /tmp: Verzeichnis für temporäre Dateien /usr: Programme für Benutzer /usr/local: Lokale Erweiterungen, nicht Bestandteil des Grundsystems /usr/share: Architekturunabhängige Dateien /usr/share/man: Manual pages, man1-man9 /var: variabel, Änderbare Daten zur Laufzeit liegen hier
Das /proc-Verzeichnis soll nur Informationen über die Prozesse beinhalten, diese liegen innerhalb von /proc in den Verzeichnissen die der Prozess-ID entsprechen.
Einen Sonderfall stellt /proc/self dar, es zeigt immer auf den eigenen Prozess.
Im /proc-Dateisystem stehen auch Kernel-Einstellungen. Diese haben hier eigentlich nichts zu suchen. Das /proc-Verzeichnis hat sich aber als gut geeignete Schnittstelle zu den Kernel-Parametern herausgestellt.
Seit Kernel 2.6 sind diese nach /sys verschoben worden. Aus Gründen der Kompatibilität existieren die Einträge im /proc-Verzeichnis jedoch noch immer.
Unterhalb von /usr/local gibt es fast die gesamte Hierarchie noch einmal. Diese ist für eigene lokale Erweiterungen des Systems gedacht um diese klar von der Distribution oder bei kommerziellen Unixen von den Herstellerprogrammen zu trennen. Allerdings halten sich die meisten Distributionen nicht immer daran.
Es gibt verschiedene Klassen von Dateisystemen (Filesysteme).
Zu den klassischen Dateisystemen zählen z.B.: minix, ext2, msdos. Das größte Problem mit diesen Dateisystemen besteht darin, dass bei einem Crash (Kernelabsturz oder Stromausfall) die Integrität des Dateisystems nicht mehr gegeben ist. D.h. es muss hier das gesamte Dateisystem nach Inkonsistenzen durchsucht werden. Bei Festplatten aktueller Größe kann das schon einmal ein paar Stunden dauern.
Aus dieser Not entstanden die journaling Dateisysteme wie ext3, jfs, reiserfs, xfs. Diese führen ein Journal in dem vor der Ausführung einer Aktion auf der Festplatte diese dort vermerkt wird. Nach der Beendigung wird der Vermerk aus dem Journal entfernt.
Findet nun ein Crash statt, so müssen nur noch die offenen Bereiche die im Journal noch vermerkt sind auf Inkonsistenzen überprüft werden. Ein Dateisystemcheck dauert jetzt lediglich ein paar Sekunden.
Jfs ist das erste Journaling Dateisystem von IBM, es ist aber erst recht spät in den Linux-Kernel aufgenommen worden. Das ext3 ist nur eine Erweiterung des ext2-Systems um ein Journal. Der Vorteil ist, dass ein ext2-System problemlos in ein ext3 umgewandelt werden kann. Das geht übrigens auch umgekehrt!
Xfs ist das Dateisystem von SGI, dass sich bei Irix bewährt hat. Es gilt als das Schnellste aller journaling Dateisysteme.
Reiserfs war das erste als stabil deklarierte journaling Dateisystem von Linux. Es ist bei vielen kleinen Dateien recht performant. Ein Nachteil war aber, dass es eigentlich am Anfang nicht stabil war, da hatte es wohl jemand zu eilig gehabt es in den Kernel zu bekommen. Ein Crash eines reiserfs Systems führte nicht selten zum Verlust des gesamten Festplatteninhaltes! Von daher hat dieses Dateisystem bei vielen noch einen schlechten Ruf. Mittlerweile scheint es aber wirklich stabil zu sein.
Die bislang beste Erfahrung habe ich noch immer mit xfs gemacht, dies setze ich seit weit über 6 Jahren ohne irgendwelche Probleme ein.
Es gibt dann noch die Speicher (Memory) Dateisysteme, shfs sowie eine ramdisk. Das shfs wird häufig für das /tmp-Verzeichnis verwendet. Die Dateien die hier normalerweise abgelegt werden sind nur temporäre Auslagerungen von Programmen. D.h. die Wahrscheinlichkeit ist recht hoch, dass diese vom Programm auch wieder gelesen werden. Das erhöht dann natürlich die Ausführungsgeschwindigkeit denn es gibt wohl kein schnelleres Dateisystem als eines das im Hauptspeicher liegt.
Dann existieren noch Pseudo-Dateisysteme: procfs, devfs, usbfs, sysfs. Dies sind keine Dateisysteme die auf einer Festplatte oder im Hauptspeicher abgebildet werden sondern sind rein virtuelle Dateisysteme die der Kernel bereitstellt.
Das procfs wird für die Bereitstellung der Prozessinformationen verwendet, das sysfs für die Kernelparameter und devfs ist eigentlich für die Devices gedacht. Die Dateien in diesem Verzeichnis stellen eine Kernel-Schnittstelle zur Hardware dar. Allerdings hat sich dieses Dateisystem bislang noch nicht durchgesetzt.
Das usbfs ist ein Dateisystem, dass der Kernel bereitstellt und das Auslesen von USB-Informationen erlaubt. Das Programm lsusb wertet dieses aus.
Und schließlich existieren noch die Netzwerkdateisysteme NFS, SMB/CIFS, AFS und Coda.
NFS, das Network File System ist das älteste Netzwerk Dateisystem und stammt von Sun. Es ist heute noch das Standard Dateisystem für Netzwerke innerhalb von Unixsystemen.
AFS ist gewissermassen eine Erweiterung von NFS, es benutzt Kerberos und ACL's für die Sicherheit sowie lokale Caches.
Lokale Caches verwendet auch Coda wodurch Dateien z.B. auf einem Notebook gecached und später beim reconnect des Notebooks mit dem Server abgeglichen werden.
SMB/CIFS ist das hauptsächlich von Microsoft verwendete Protokoll für ein Netzwerk-Dateisystem. SMB steht für Server Message Block. Das Linuxpaket für dieses Dateisystem heißt samba, der Name war der Erste in einem Lexikon der die Buchstaben S, M und B enthielt.
CIFS ist das Common Internet File System und ist die Weiterentwicklung von SMB. Konsequenter Weise beherrscht samba dieses Dateisystem ebenfalls, es ist zur Abwechslung einmal ein offener Standard von Microsoft, siehe
http://www.ubiqx.org/cifs/rfc-draft/draft-leach-cifs-v1-spec-02.html
Allerdings hat es dieser Draft nie zu einem offiziellen Standard geschafft, der Draft ist obendrein expired.
Da die Philospohie von Unix besagt, dass (fast) alles eine Datei ist, so gibt es auch enstsprechend reichlich verschiedene Dateitypen.
Das Programm /bin/ls (list) mit der Option -l liefert eine Ausgabe des aktuellen Verzeichnisses in der Langversion. Dabei gibt das erste Zeichen einer jeden Zeile Auskunft über die Dateiart:
Ein hilfreiches Kommando ist file, dies gibt an um welche Art von Datei es sich handelt und bei normalen Dateien welche Form von Daten enthalten sind, z.B.
majestix:~$ file Lion_seul.mpg Lion_seul.mpg: MPEG system stream data
Wobei in diesem Fall die Endung schon helfen würde. Aber file ist ein bischen intelligenter, es analysiert die (ersten) Bytes der Datei und versucht anhand von sogenannten Magic-Codes zu bestimmen was für eine Datei es wirklich ist. Ein simples Umbenennen hilft hier nicht um den Typ zu ändern im Gegensatz z.B. bei einem anderen bekannten Betriebssystem:
majestix:~$ mv Lion_seul.mpg Lion_seul.jpg majestix:~$ file Lion_seul.jpg Lion_seul.jpg: MPEG system stream data
Die Dateien sind zusätzlich mit Zugriffsrechten versehen. Hier gibt es normalerweise drei verschiedene Bereiche. Das sind die nächsten neun Zeichen bei einem ls -l. Die ersten drei Zeichen sind für den Eigentümer der Datei, die nächsten für die Gruppe und die letzten für alle anderen.
Der Name des Eigentümers muss in der Datei /etc/passwd stehen, ansonsten steht hier nur eine User ID. Analog ist das mit der Gruppe, diese muss in /etc/group stehen. Der Rest bezieht sich auf alle die nicht in die ersten beiden Bereiche fallen.
Das erste Zeichen ist ein r (read) für Leserechte oder ein - für nicht lesbar, das nächste ist ein w (write) für die Schreibrechte und das dritte ist für ausführbare Dateien: x (execute).
Bei Verzeichnissen werden die Leserechte benötigt um das Verzeichnis lesen zu können. Aber zusätzlich wird hier das x benötigt um in das Verzeichnis wechseln zu können. Allein mit Leserechten können nur die Programmnamen im Verzeichnis erhalten werden, keine weiteren Informationen wie Größe oder Datum.
Allein mit x-Rechten kann zwar in das Verzeichnis gewechselt werden, es besteht aber nicht die Möglichkeit die Dateien aufzulisten.
Es gibt noch zwei Sonderzeichen, zum einen das SUID (set user ID, also setze die Benutzer ID) bzw. SGID (set group ID, setze die Gruppen ID): s. In diesem Fall erhält der ausführende eines Programmes die Rechte entweder des Besitzers oder der Gruppe. Dies funktioniert aber nicht bei Shellskripten!
Das andere Sonderzeichen ist das sticky (klebrige) Bit. Der Name rührt daher, dass Programme mit diesem Bit im Speicher verbleiben sollen, sie kleben am RAM. Dank Paging-Mechanismen, das geschickte Auslagern einzelner nichtbenötigter Bereiche, ist das nicht mehr notwendig und funktioniert demzufolge bei Dateien nicht mehr.
Allerdings hat dieses Bit bei Verzeichnissen noch eine Bedeutung: Ist das t-Bit gesetzt, dann darf entgegen der üblichen Zugriffsrechte nur derjenige eine Datei verändern/löschen der sie auch angelegt hat. Das ist für temporäre Verzeichnisse wie /tmp oder /var/tmp wichtig. Dieses Verzeichnis darf per default jeder beschreiben, also Dateien editieren oder löschen.
Damit wird auch die Bedeutung des Schreibrechts w für Verzeichnisse deutlich. Nur wer dieses hat, darf Dateien anlegen oder löschen.
Und zu guter letzt gibt es auch noch ACL's, hier können die Rechte granularer vergeben werden als via Eigentümer/Gruppe/Rest. Da diese Rechte aber bei einem normalen ls -l nicht angezeigt werden sind sie auch nicht sehr beliebt. Es ist lediglich im Langformat anhand des Plus-Zeichens nach den klassischen Zugriffsrechten zu erkennen, dass ACLs gesetzt sind.
Die ACLs können mit setfacl gesetzt und mit getfacl ausgelsen werden, z.B.:
majestix:~$ setfacl -m u:lug:- Datei majestix:~$ getfacl Datei # file: Datei # owner: geschke # group: geschke user::rw- user:lug:--- group::r-- mask::r-- other::r-- majestix:~$ ls -l Datei -rw-r--r--+ 1 geschke geschke 23 2008-11-18 17:51 Datei
Dass diese ACLs auch wirklich greifen kann leicht getestet werden indem die User-ID von lug angenommen wird:
majestix:~$ su lug Password: lug@majestix:/home/geschke$ ls -l Datei -rw-r--r--+ 1 geschke geschke 23 2008-11-18 17:51 Datei lug@majestix:/home/geschke$ cat Datei cat: Datei: Keine Berechtigung
Der Hauptgrund für diese erweiterten Rechte liegt wohl darin, dass Windows solche Granularitäten zuläßt. (Oder auch nicht, es gibt viele Programme unter Windows die diese gesonderten Rechte einfach ignorieren, siehe z.B.: http://security.tombom.co.uk/shatter.html)
Der Bootloader sitzt gewöhnlich in den ersten 512 Bytes einer Festplatte, Disktte oder CD-Rom. Hierin befindet sich auch noch die Partitionstabelle.
Daher ist verständlich, dass die meisten Bootloader in mehr als einem Schritt arbeiten müssen. In der ersten Stufe wird nur ein minimaler Bootloader geladen, der in der zweiten Stufe den eigentlichen Bootloader nachlädt. Dieser liegt gewöhnlich in /boot.
Dieser lokalisiert den Kernel und lädt ihn in den Hauptspeicher wo er entpackt wird, je nach Art des Kernels an unterschiedliche Stellen, make zImage versus make bzImage.
Typische Bootloader von Linux sind lilo (linux loader) und grub (grand unified bootloader). Der erste ist der älteste und hatte lange Zeit Probleme bei IDE-Festplatten den Kernel jenseits von Zylinder 1024 zu booten. Daher war /boot meist die erste kleine Partition bzw. sie wurde daher überhaupt eingeführt. Grub stammt aus dem GNU-Hurd Projekt und besitzt auch die Fähigkeit über das Netzwerk zu booten.
Das erste was der Kernel durchführt ist die CPU und den Hauptspeicher (RAM) zu initialisieren. Danach werden die diversen Hardware-Bestandteile erkannt und initialisiert. Dazu muss der entsprechende Treiber auch im Kernel enthalten sein. Die Kernelmeldungen können mit dem Programm dmesg ausgegeben werden und geben manchmal einen Hinweis darauf warum etwas nicht korrekt funktioniert.
Wenn Kernelmodule beim Booten benötigt werden dann kann eine ''Initial Ramdisk'' (initrd) gemounted werden. Über diese können Module geladen werden die z.B. notwendig sind um die Root-Partition zu mounten. Die Verwendung des initrd muss aber explizit in den Kernel kompiliert werden.
Der nächste Schritt besteht im Mounten der root-Partition (/) und dem Starten des init Prozesses. Dieser ist immer der erste (Userland-) Prozess der gestartet wird und hat daher die Prozess-ID (PID) 1:
majestix:~$ ps waux |head -2 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 1492 176 ? S Aug10 0:07 init [2]
Das gilt auch wenn bereits Kernelprozesse die vorher gestartet wurden in der Prozesstabelle stehen. Die PID von init bleibt traditionell bei eins.
ps gibt die Prozessliste aus, die Optionen w für weite, also lange Ausgabe, a für alle Prozesse, u für die Benutzerangabe (user) und x für Daemonen bzw. Prozesse ohne controlling tty. Dies ist die BSD-Syntax, die SysV-Syntax gibt es auch, dann werden die Optionen mit - angegeben, z.B.:
majestix:~$ ps -ef |head -2 UID PID PPID C STIME TTY TIME CMD root 1 0 0 Aug10 ? 00:00:07 init [2]
Aber meistens ist die BSD-Variante besser zu lesen und ist daher meist beliebter.
Der Wert am Ende in Klammern gibt den aktuellen Runlevel an. Dieser wird normalerweise unter Unix mit who -r ausgegeben:
majestix:~$ who -r run-level 2 Aug 10 12:11 last=S
Früher gab es diese Funktion aber noch nicht in who (bei Linux!). Dafür existiert dann das Programm runlevel.
Das geht natürlich nur bei SysV basierten Systemen, BSD-Systeme haben keinen Runlevel...
Der Prozess der als erstes gestartet wird ist der init-Prozess. Dieser wertet die Datei /etc/inittab aus (SysV, BSD startet direkt /etc/rc)
Es gibt auch BSD-artige init's bei Linux, insbesondere Slackware verwendete dieses Konzept.
Heutzutage verwenden alle Linux-Distributionen die SysV-Version von init die über /etc/inittab gestartet wird. Diese wird sequentiell abgearbeitet. Slackware verwendet auch diese Version um dann über /etc/inittab das BSD-Verhalten zu simulieren.
Die ersten 2 Zeichen sind nur ein Identifier der eigentlich nicht mehr verwendet wird aber aus historischen Gründen noch existiert. Bei tty's wurde das 2. Zeichen, dass eine Ziffer sein mußte als Nummer des Devices verwendet, also z.B. aus T3 folgte das Device ttyS3.
Der zweite Wert ist der Runlevel, der dritte die Aktion, die init ausführen soll und der letzte Eintrag ist der Prozess der von init gestartet werden soll:
Dies hier legt nur den gewünschten Runlevel fest.
# The default runlevel. id:2:initdefault:
Die nächsten Zeilen werden immer ausgeführt, da hier hier die Aktion sysinit steht.
# Boot-time system configuration/initialization script. # This is run first except when booting in emergency (-b) mode. si::sysinit:/etc/init.d/rcS
D.h. bei jedem Boot wird das Shellskript /etc/init.d/rcS gestartet:
majestix:~$ file /etc/init.d/rcS /etc/init.d/rcS: Bourne shell script text executable
Das Skript lädt ein paar Voreinstellungen und startet dann alle Skripte in /etc/rcS.d/ die mit S?? anfangen mit der Option start:
# # Call all parts in order. # for i in /etc/rcS.d/S??* do # Ignore dangling symlinks for now. [ ! -f "$i" ] && continue case "$i" in *.sh) # Source shell script for speed. ( trap - INT QUIT TSTP set start . $i ) ;; *) # No sh extension, so fork subprocess. $i start ;; esac done
$i enthält hier die Dateinamen, die case-Zeile nimmt eine Fallunterscheidung vor: Endet die Datei auf .sh, so wird die Datei gesourced, d.h. es handelt sich vermutlich um ein Shellskript und das Starten einer zusätzlichen Shell wird gespart was dann schneller abläft. Auf diese Weise können aber auch Umgebungsvariablen über Shellskripte gesetzt werden die für die anderen Shellskripte dann gesetzt sind. * paßt auf alles andere. Da $i den Dateinamen mit vollem Pfad enthält funktioniert hier auch der Aufruf.
Eigentlich müßte es S[0-9][0-9]* heißen, also nur die Skripte starten, die mit S und zwei Ziffern anfangen. Die Abarbeitung erfolgt in der Reihenfolge der Nummern, also S01 vor S99. Die Sortierung erledigt die Shell automatisch durch die Expansion.
Die Dateien in /etc/rcS.d/ sind gewöhnlich symbolische Links auf die eigentlichen Start- bzw. Stoppskripte in /etc/init.d/.
Der nächste Eintrag wird nur ausgeführt wenn in den sogenannten Singleuser-Modus gestartet wird. In diesem Modus kann sich gewöhnlich nur der Benutzer root einloggen, es gibt dann meist auch kein Netzwerk oder virtuelle Konsolen. Da /etc/rcS.d/ (s.o.) vorher ausgeführt wird kann das Verhalten natürlich geändert werden, daher auch das Wort meist:
# What to do in single-user mode. ~~:S:wait:/sbin/sulogin
Dies wird meistens nur für Systemarbeiten benutzt, wenn z.B. andere Benutzer explizit das System nicht benutzen sollen, z.B. wenn die Home-Verzeichnisse auf eine neue Partition verschoben werden sollen. Da wäre es nicht gut, wenn gleichzeitig User arbeiten würden. Oder es wird neue Hardware installiert und konfiguriert. Bevor dann bei jedem Reboot die Benutzer aufgefordert werden müssen sich wieder auszuloggen und die Arbeit zu beenden ist es besser sie explizit nicht zuzulassen. Ein Vorteil ist auch, dass die meisten Startskripte nicht mehr ausgeführt werden, der Login-Prompt erscheint deutlich schneller.
Die nächsten Zeilen sind für die verschiedenen Runlevel, es wird einfach nur das Skript /etc/init.d/rc mit dem Runlevel aufgerufen:
l0:0:wait:/etc/init.d/rc 0 l1:1:wait:/etc/init.d/rc 1 l2:2:wait:/etc/init.d/rc 2 l3:3:wait:/etc/init.d/rc 3 l4:4:wait:/etc/init.d/rc 4 l5:5:wait:/etc/init.d/rc 5 l6:6:wait:/etc/init.d/rc 6
Bei einem Runlevel von 2 wird nur /etc/init.d/rc 2 ausgeführt. wait gibt hierbei an, dass init warten soll bis alle Skripte abgearbeitet worden sind bevor die Weiterverarbeitung fortschreitet.
/etc/init.d/rc 2 startet alle S??* Skripte in /etc/rc2.d/ mit der Option start, wie es zu erwarten war.
Weiter geht es mit der Definition was bei der Tastenkombination CTRL-ALT-DEL passieren soll:
# What to do when CTRL-ALT-DEL is pressed. ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now
Diese Tastenkombination wird aber gewöhnlich vom X11-Server abgefangen.
Weiter geht es mit dem Starten der virtuellen Konsolen:
1:2345:respawn:/sbin/getty 38400 tty1 2:23:respawn:/sbin/getty 38400 tty2 3:23:respawn:/sbin/getty 38400 tty3 4:23:respawn:/sbin/getty 38400 tty4 5:23:respawn:/sbin/getty 38400 tty5 6:23:respawn:/sbin/getty 38400 tty6
D.h. die virtuellen Konsolen gibt es nur im Runlevel 2 oder 3. Der respawn-Eintrag besagt, dass die Programme, in diesem Fall getty, neu gestartet werden sollen wenn sie sich beenden.
Das Programm getty öffnet einen Terminal-Port tty, der Name geht auf die Anfänge zurück als die Server noch über Teletyper also Fernschreiber angebunden waren. Die Tastatur war der Fernschreiber, der Bildschirm war einfach das gedruckte Papier. Dieser Prozess präsentiert einen Login-Prompt. Das Umschalten zwischen den Text-Konsolen funktioniert mit ALT-F1 bis ALT-F6, es werden oben 6 Terminal-Sitzungen gestartet.
Auf der nächsten sitzt gewöhnlich der X11-Server, d.h. mit ALT-F7 wird zum X11-Bildschirm gewechselt. Der Wechsel vom X11-Bildschirm auf die erste Konsole funktioniert mit der Tastenkombination CTRL-ALT-F1. Der Grund liegt einfach darin, dass unter X11 viele Programme die ALT-F? Kombinationen anderweitig nutzen.
Dann gibt es noch zwei weitere interessante Einstellungen:
# Example how to put a getty on a serial line (for a terminal) # T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100
Dies startet in den Runleveln 2 und 3 einen getty auf der seriellen Leitung, d.h. es besteht die Möglichkeit sich dann z.B. via Nullmodemkabel einzuloggen.
Sollen die Kernelmeldungen auf die serielle Konsole umgelenkt werden, so muß das im Kernel einkompiliert sein und via append-Zeile aktiviert werden. Ferner sollte dann auch der Bootloader auf die serielle Leitung umgestellt werden.
Und schließlich:
# Example how to put a getty on a modem line. # #T3:23:respawn:/sbin/mgetty -x0 -s 57600 ttyS3
Dies würde ein Modem an ttyS3 ansteuern. Der mgetty würde auf eingehende Anrufe warten und dann einen Login-Prompt via Modem präsentieren.
Zum einen gibt es die klassischen Handbuchseiten (manual pages), diese existieren schon seit der allerersten Unix-Version und sind immer einheitlich aufgebaut. Das Format ist nroff und wird mit der speziellen Option -man aufgerufen um die Datei in das bekannte, lesbare Format umzuwandeln. Dieses erledigt aber das man-Kommando automatisch.
Die manual pages liegen gewöhnlich unter /usr/share/man/, dort gibt es für jede Sektion ein Unterverzeichnis man1-man9 in dem die eigentlichen Seiten im nroff-Format liegen.
Der Aufbau ist nahezu immer derselbe, zuerst erfolgt der Name als Einzeiler mit kurzem Kommentar. Danach kommt eine kurze Auflistung in welcher Form z.B. das Programm aufgerufen werden kann (SYNOPSIS).
Anschließend folgt eine ausführlichere Beschreibung sowie eine Auflistung der Optionen mit deren Funktion. Zum Schluss gibt es noch die Autoren, eine Liste von Handbuchseiten die verwandt sind (SEE ALSO) sowie ein Abschnitt mit bekannten Fehlern (BUGS). Letzterer ist insofern interessant, dass sie überhaupt existiert. Die meisten Systeme verschweigen lieber die bekannten Fehler. Hier steht aber auch oft, wie die Fehler umgangen werden können oder warum sie nicht behoben wurden: Manchmal ist es nicht klar, wie dies erfolgen sollte.
Es besteht auch die Möglichkeit nur nach einem Stichwort zu suchen. Dafür bieten sich die zwei Programme man -k Stichwort bzw. apropos Stichwort an, z.B.:
majestix:~$ man -k fifo fifo (4) - first-in first-out special file, named pipe mkfifo (1) - make FIFOs (named pipes) mkfifo (3) - make a FIFO special file (a named pipe) perlipc (1) - Perl interprocess communication (signals, fifos, pipes, safe subprocesses, sockets, and semaphores)
Das erste ist das Programm, Bibliotheksaufruf oder Dateiname der manual page basierend auf der Sektion, diese ist in runden Klammern angegeben. Danach folgt die Kurzbeschreibung.
Existiert eine Handbuchseite in verschiedenen Sektionen (z.B. hier mkfifo) so kann beim Aufruf der manual page diese Sektion einfach mitangeben werden:
man 3 mkfifo
Es gibt bei Linux 9 Sektionen die nach den Kapiteln des ersten Handbuch über Unix benannt wurden. Die Sektion 9 ist linuxspezifisch, die Sektion 6 kam mit BSD ins Spiel:
Beenden kann man die Manual-Pages mit q. Das ist übrigens ein gutes Beispiel für die Verwendung verschiedener Programme. nroff wird verwendet um die Datei in das lesbare Format umzuwandeln, angezeigt werden diese mit less bzw. dem Programm das in der Umgebungsvariablen PAGER angegeben ist. Solaris verwendet per default more, das bietet nicht die Möglichkeit wieder nach oben zu blättern, ein PAGER=less bewirkt dann ein Verhalten wie bei Linux.
Da die manual pages aus den Urzeiten von Unix stammen gab es auch Bestrebungen, hauptsächlich von der FSF, der Free Software Foundation, bekannt für GNU, ein besseres System zu verwenden: Die info Seiten, diese sind querverlinkt ähnlich wie HTML. Allerdings sind diese nicht unbedingt gut, d.h. intuitiv zu bedienen.
Der Aufruf info --apropos Suchbegriff hat ein ähnliches Verhalten wie man -k Suchbegriff, z.B.:
majestix:~$ info --apropos "stream editor" "(gawk)Simple Sed" -- stream editors <1> "(gawk)Field Splitting Summary" -- stream editors "(sed)Introduction" -- Stream editor
Mit CTRL-X CTRL-C kann das Programm info verlassen werden, in diesem Fall ist es ein emacs. Kein Wunder, es kommen emacs und info pages aus dem gleichen Stall(man).
Eine weitere meist sehr gute Quelle für Informationen sind die FAQ's (Frequently Asked Questions, häufig gestellte Fragen). Die Wurzeln gehen auf die Anfänge von Linux in newsgroups zurück. Hier wurden häufig immer die gleichen Fragen gestellt, die schon mehrfach beantwortet worden sind. Daraufhin haben sich einige bereit erklärt diese Fragen und Antworten zu sammeln und zu veröffentlichen.
Jeder sollte dann erst in eine FAQ schauen bevor er eine Frage stellt. Im anderen Fall gibt es meist unschöne Antworten wie RTFM. Aus den FAQ's wurden dann später Anleitungen wie etwas z.B. einzurichten ist. Das sind die HOWTO's (Wie geht es). Im Linux-Umfeld sind diese unter:
zu finden, the linux documentation project.
Informationen den Kernel betreffend und insbesondere wie diverse Hardware angesprochen/konfiguriert werden kann befindet sich im Kernel-Baum. Diese liegt gewöhnlich unter
/usr/src/linux/Documentation
und enthält Textdateien.
Eine weitere Quelle sind manchmal die Konfigurationsdateien selber, diese sind oft ASCII-Dateien und meistens sind die Einträge mit erläuternden Kommentaren versehen.
Schließlich gibt es noch
und letztendlich den Standard des Internets: RFC's (request for comments). Dieses können unter
gefunden werden oder unterhalb von http://www.ietf.org/. Hier gibt es verschiedene Stufen von Draft, Informal bis Standard. Sie sind von der Internet Engeneering Task Force (IETF) ins Leben gerufen worden um den Standart des Internets verbindlich festzulegen.
Jeder hat sich an diese Standards zu halten! Nur leider gibt es Firmen, die dies nicht tun und es gibt keine Instanz die diese Einhaltung überwacht oder sogar erzwingen würde.
Wer sich aber daran hält, der darf sich RFC-konform nennen.
Hier wird z.B. der Aufbau der Protokolle IP, ICMP, TCP, UDP, HTTP, SMTP, ... festgehalten.
Zuerst einmal ein paar Anmerkungen zu den Kommandozeilentools.
Die meisten Kommandozeilentools verwenden kurze Optionen (1 Zeichen) und/oder lange Optionen. Da klassischerweise Optionen mit einem - Zeichen anfangen und kombiniert werden können, mußte für die Langfassung ein neues Symbol verwendet werden. Der Einfachheit halber sind das 2 -- Zeichen.
Z.B. kann statt
ps -e -l -f
auch
ps -elf
geschrieben werden.
Bei der Langfassung gibt es bei nahezu allen Programmen eine Option um eine kurze Hilfe zu bekommen: --help, bei der Kurzfassung ist dies oft -h, allerdings kommt dann auch oft die Ausgabe: unbekannte Option, versuche --help.
Manche Programme verzichten auch auf das Minus-Zeichen, so z.B. tar oder ps. Bei letzterem wiederum wird dadurch zwischen zwei Modi unterschieden, mit Minus-Zeichen ist es SysV-Syntax und ohne die BSD-Syntax. Entsprechend unterschiedlich wirken auch die Optionen.
Beenden bzw. Abbrechen von Programmen kann meistens auf verschiedene Weisen erfolgen:
Hier werden nur einige der wichtigsten Tools vorgestellt. Die Wichtigsten sind gewöhnlich die Kürzesten (2 Buchstaben).
Beispiele:
mount zeigt an, was wo und wie eingehängt ist:
$ mount /dev/hda1 on / type xfs (rw) proc on /proc type proc (rw) devpts on /dev/pts type devpts (rw,gid=5,mode=620) /dev/hda6 on /home type xfs (rw) /dev/hda7 on /opt type xfs (rw) sysfs on /sys type sysfs (rw) usbfs on /proc/bus/usb type usbfs (rw)
Dies zeigt Auslastung der Partitionen an:
$ df Filesystem 1K-blocks Used Available Use% Mounted on /dev/hda1 7995536 5170040 2825496 65% / /dev/hda6 4091740 3430416 661324 84% /home /dev/hda7 2935060 409508 2525552 14% /opt
Anzeigen der Belegung einzelner Verzeichnisse in kB:
$ du -k -s /usr/share/man/man* 12172 /usr/share/man/man1 868 /usr/share/man/man2 14468 /usr/share/man/man3 428 /usr/share/man/man4 1408 /usr/share/man/man5 408 /usr/share/man/man6 652 /usr/share/man/man7 2192 /usr/share/man/man8 1428 /usr/share/man/man9
Erzeugen einer Datei aus binären Nullen mit 512 Bytes (bs: block size)
$ dd if=/dev/zero of=/var/tmp/empty bs=512 count=1
Sichern der Home-Verzeichnisse in die Datei /var/tmp/home.tar
$ tar cvf /var/tmp/home.tar /home
Der vi hat zwei Modi, einen Insert-Modus in dem Text über die Tastatur eingegeben werden kann und einen Command-Modus. Hier kann z.B. mit den Tasten h, j, k, l im Text navigiert werden, x löscht das Zeichen unter dem Cursor, i schaltet in den Insert-Modus und die Escape-Taste wechselt in den Command-Modus zurück. ZZ speichert die Datei ab und beendet den vi, alternativ kann auch die Tastenkombination :wq! verwendet werden. Das Ausrufezeichen forciert ein Abspeichern was bei ZZ nicht der Fall ist!
Der emacs ist sehr mächtig, er enthält sogar einen Psychiater: M-X doctor
M-X ist das Meta-X, d.h. gewöhnlich ALT-X und man landet in dem unteren Mini-Buffer des emacs'. Er hat auch Funktionen zum highlighten, also dem farbigen Hervorheben von Textpassagen, Syntaxchecks, er kann Compiler und Debugger aufrufen und vieles mehr.
Spötter behaupten der Emacs sei ein eigenes Betriebssystem, nur leider ohne Editor.
Beispiele:
Das Zählen aller Startskripte aus rc2.d geht mittels:
$ ls /etc/rc2.d/ | grep ^S[0-9][0-9] | wc -l 42
Ausgeben alle Startdateien aus /etc/init.d die mit r beginnen, es werden nur der Name und die Größe ausgegeben:
$ ls -l /etc/init.d/r* |awk '{print $9 " " $5}' /etc/init.d/rc 2235 /etc/init.d/rcS 1190 /etc/init.d/reboot 197 /etc/init.d/rinetd 1182 /etc/init.d/rmnologin 261 /etc/init.d/rsync 2026
Beispiel zum Unterschied von which und type:
$ which bash /bin/bash $ which pwd /bin/pwd $ type bash bash is /bin/bash $ type pwd pwd is a shell builtin
In nachfolgenden Fall handelt es sich um ein Programm vom Typ ELF, executable and linkable format. Das ist das aktuelle Format von ausführbaren Programmen und stammt dem System V (SysV) ab. Es ist sehr gut für das dynamische Linken gegen Bibliotheken geeignet.
Ferner ist die Datei im little endian Format, least significant bits (LSB) im Gegensatz zu big endian, most significant bits (MSB). Die Aussage bezieht sich auf die Reihenfolge wie die Bytes abgespeichert werden. Big und little endian geht zurück auf Gullivers Reisen, dort gab es die Einen, die Ihre Eier immer an dem dicken Ende zuerst aufgeschlagen haben, die anderen an dem dünnen Ende.
Stripped bezieht sich darauf, dass alle Symbole für ein Debugging abgestreift wurden. Das macht die Datei schlanker, erschwert aber die Fehlersuche bei Problemen.
$ file /bin/bash /bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), stripped
Soviel zu den statisch gelinkten Programmen in /bin: Unter Linux sind diese gegen den Standard dynamisch gelinkt. Aber es kann gesehen werden, dass alle Abhängigkeiten auf der root-Partition liegen:
$ ldd /bin/bash ldd /bin/bash libncurses.so.5 => /lib/libncurses.so.5 (0x4002a000) libdl.so.2 => /lib/libdl.so.2 (0x40069000) libc.so.6 => /lib/libc.so.6 (0x4006c000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
Hier ist ein Beispiel zum Auffinden der einkompilierten Lage der sshd_config Datei im secure shell daemon (sshd):
$ strings /usr/local/sbin/sshd |grep sshd_config /usr/local/etc/sshd_config
Beispiele:
pstree, -A für ASCII Ausgabe, alles fängt mit init an, der Windowmanager ist via gdm (gnome display manager) gestartet worden.
$ pstree -A init-+-acpid |-atd |-bash-+-bash---Xprt | `-bash |-cardmgr |-cron |-dictd |-events/0 |-famd |-gdm---gdm-+-XFree86 | `-fvwm2-+-FvwmAuto | |-FvwmPager | |-ssh-agent [...]
Auflisten des Prozesses elvis:
$ ps wa |grep elvis 8866 pts/0 S+ 0:05 /usr/bin/elvis LG12
Die offenen Dateien von elvis sind:
$ lsof -P 8866 COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME elvis 8866 geschke cwd DIR 3,6 4096 235120 /home/geschke/LUG elvis 8866 geschke rtd DIR 3,1 4096 128 / elvis 8866 geschke txt REG 3,1 521400 22195163 /usr/bin/elvis [...]
Beim TYPE ist DIR ein Verzeichis (directory), REG ist eine reguläre Datei, DEVICE gibt an auf welchem Device (Major, Minor) die Datei liegt, in diesem Fall ist es /dev/hda1 bzw. /dev/hda6:
$ ls -l /dev/hda[16] brw-rw---- 1 root disk 3, 1 Mar 14 2002 /dev/hda1 brw-rw---- 1 root disk 3, 6 Mar 14 2002 /dev/hda6
Das erste ist die root-Partition, das andere die home-Partition:
$ df / /home Filesystem 1K-blocks Used Available Use% Mounted on /dev/hda1 7995536 5168936 2826600 65% / /dev/hda6 4091740 3540664 551076 87% /home
(Und ja, ich sollte mal wieder aufräumen...)
Beispiele:
Hier kann die MAC-Adresse (HWaddr) der Ethernetkarte gefunden werden, die gesetzte IP-Adresse sowie die Broadcast-Adresse und die Netzmaske sowie Statistik über die ein- und ausgegangen Pakete (RX: Receive, TX: Transmit)
# ifconfig eth0 eth0 Link encap:Ethernet HWaddr 00:A0:CC:D8:AC:17 inet addr:192.168.1.18 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:22211 errors:0 dropped:0 overruns:0 frame:0 TX packets:22347 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:13683545 (13.0 MiB) TX bytes:3406355 (3.2 MiB) Interrupt:9 Base address:0x4700
Hier kann gesehen werden, dass 100MBit im Full-Duplex Modus ausgehandelt (negotiated) worden sind und der Link-Status ok ist:
# mii-tool eth0 eth0: negotiated 100baseTx-FD flow-control, link ok
Auflisten der bekannten Zuordnung zwischen MAC und IP-Adresse geht auch relativ leicht:
# arp -a majestix.physik.home (192.168.1.5) at 00:E0:4C:00:82:9F [ether] on eth0
Mitsniffen des ARP Verkehrs, hier wird nach der MAC-Adresse von 192.168.1.5 gefragt und just dieser Computer antwortet:
# tcpdump arp 22:39:10.209273 arp who-has 192.168.1.5 tell debix.physik.home 22:39:10.209397 arp reply 192.168.1.5 is-at 0:e0:4c:0:82:9f
Normalerweise wird nur der Netzwerkverkehr von der Ethernetkarte angenommen, der auch für diese Karte bestimmt ist. Soll alles gezeigt werden, so muß die Karte in den promiscous Modus gesetzt werden. tcpdump macht dies automatisch, aus dmesg:
device eth0 entered promiscuous mode
Das nützt aber wenig, wenn der Anschluß an das Netzwerk über einen Switch erfolgte, dieser leitet die anderen Netzwerkpakete nicht weiter.
ethereal hat eine graphische Oberfläche und bietet bessere Analysemöglichkeiten der höheren Protokollebenen. Allerdings sind damit auch einhergehende Sicherheitslücken möglich. Daher bietet sich das Mitschneiden in eine Datei mit tcpdump (Option -w Dateiname) an. Diese Datei kann dann von ethereal ausgewertet werden, dazu muß ethereal nicht mehr mit root-Rechten laufen!
nmap listet die offenen Ports eines entfernten Computers auf. Per default sind das nur TCP-Ports, es geht aber auch mit UDP und es gibt diverse Methoden das Scannen zu verschleiern:
# nmap 192.168.1.18 Starting nmap V. 3.00 ( www.insecure.org/nmap/ ) Interesting ports on debix-1.physik.home (192.168.1.18): (The 1589 ports scanned but not shown below are in state: closed) Port State Service 9/tcp open discard 13/tcp open daytime 21/tcp open ftp 22/tcp open ssh 23/tcp open telnet 25/tcp open smtp 37/tcp open time 79/tcp open finger 111/tcp open sunrpc 113/tcp open auth 515/tcp open printer 866/tcp open unknown Nmap run completed -- 1 IP address (1 host up) scanned in 1 second
netstat listet die offenen Ports des eigenen Computers auf. Hier ergibt sich für TCP bei 192.168.1.18:
# netstat -ta Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 *:866 *:* LISTEN tcp 0 0 *:printer *:* LISTEN tcp 0 0 *:dict *:* LISTEN tcp 0 0 *:time *:* LISTEN tcp 0 0 *:discard *:* LISTEN tcp 0 0 *:vboxd *:* LISTEN tcp 0 0 localhost:620 *:* LISTEN tcp 0 0 *:daytime *:* LISTEN tcp 0 0 *:finger *:* LISTEN tcp 0 0 *:sunrpc *:* LISTEN tcp 0 0 *:auth *:* LISTEN tcp 0 0 *:ftp *:* LISTEN tcp 0 0 *:ssh *:* LISTEN tcp 0 0 *:telnet *:* LISTEN tcp 0 0 *:smtp *:* LISTEN tcp 0 0 localhost:5180 *:* LISTEN tcp 0 0 debix.physik.home:44062 majestix.physik.hom:ssh ESTABLISHED
Eine Verbindung besteht und zwar zu majestix via ssh.
Mithilfe von telnet kann zum Beispiel eine Verbindung einem Mailserver hergestellt werden:
$ telnet 192.168.1.5 25 Trying 192.168.1.5... Connected to 192.168.1.5. Escape character is '^]'. 220 majestix.physik.home ESMTP Sendmail 8.13.4/8.13.4/Debian-1; Sat, 10 Sep 2005 22:50:14 +0200; (No UCE/UBE) logging access from: debix-1.physik.home(OK)-root@debix-1.physik.home [192.168.1.18] quit 221 2.0.0 majestix.physik.home closing connection Connection closed by foreign host.
Dirk Geschke, dirk@lug-erding.de