Vorlesung "UNIX"

von Prof. Jürgen Plate

1. Überblick über UNIX (2)

1.6 Das Prozeßkonzept

Jeder Prozeß, der im Betriebssystemkern aktiviert wird, erhält eine eindeutige Kennzeichnung, die sogenannte Prozeßnummer (PID). Über diese kann jeder Prozeß eindeutig identifiziert werden. Da die Prozeßnummer eine positive Integer-Zahl ist, gibt es eine maximale Prozeßnummer. Wird diese erreicht, beginnt die Zählung wieder von vorne, wobei noch existierende Prozesse mit niedriger Nummer übersprungen werden.

Ein neuer Prozeß kann nur von einem bereits laufenden Prozeß erzeugt werden. Dadurch werden, ähnlich wie beim Dateibaum, die einzelnen Prozesse im Betriebssystemkern in einer baumartigen, hierarchischen Struktur verwaltet. Jeder Kind-Prozeß ist genau einem Eltern-Prozeß untergeordnet. Ein Eltern-Prozeß kann jedoch beliebig viele Kind-Prozesse besitzen. Die Wurzel der Prozeßstruktur wird durch den Systemstart geschaffen und als init-Prozeß (PID 1) bezeichnet.

In der Regel wartet der Eltern-Prozeß auf die Beendigung seiner Kind-Prozesse. Diese Art der Prozeßsynchronisation wird als synchrone Ausführung bezeichnet, der Kind-Prozeß wird als Vordergrundprozeß ausgeführt. Bezogen auf einen Benutzer ist die Shell (Login-Shell) der Eltern-Prozeß. Alle Kommandos, die der Benutzer startet, sind Kind-Prozesse. Während diese abgearbeitet werden ruht der Eltern-Prozeß. Als asynchroner Prozeß oder Hintergrundprozeß werden solche Prozesse bezeichnet, bei denen der Eltern-Prozeß nicht auf das Ende seines Kind-Prozesses wartet, sondern parallel (quasiparallel auf einer Ein-Prozessor-Maschine) asynchron weiterläuft. Auf der Shell-Ebene kann jeder Prozeß durch Anfügen von '&' (kaufm. UND) in der Kommandozeile als Hintergrundprozeß gestartet werden.

1.6.1 Der Scheduler

UNIX ist ein Multitasking-Betriebssystem, d.h. mehrere Prozesse eines oder mehrerer Benutzer konkurrieren um die Vergabe der Rechenzeit des Prozessors. Wie viele andere Systeme auch, arbeitet UNIX nach dem Zeitscheiben-Prinzip.

Über einen Scheduling-Algorithmus zur Berechnung der Priorität erhält jeder einzelne Prozeß einen bestimmten Teil der Rechenzeit zugewiesen. D.h. der Prozeß mit der zur Zeit höchsten Priorität erhalt die CPU, wird nach einen Zeitintervall suspendiert und, falls noch nicht beendet, zu einem späteren Zeitpunkt wieder reaktiviert. Die aktuelle Priorität eines Prozesses setzt sich aus dem Produkt des CPU-Faktors und der Grundpriorität zusammen.

Die Prozeßverwaltung und Prioritätssteuerung ist recht komplex. In Stichpunkten:

--> einfach, effizient, gerecht

1.6.2 Swapping und Paging

1.6.3 Speicheraufteilung eines Prozesses im Arbeitsspeicher

Der Speicher zu einem Prozeß wird in verschiedene Segmente unterteilt:

1.6.4 Prozeßkommunikation und -Synchronisation

1.6.5 fork(), exec() und wait()

Diese Systemaufrufe haben mit der Generierung von Kindprozessen zu tun und erlauben die Synchronisation zwischen Eltern- und Kindprozessen. An dieser Stelle wird nur soweit darauf eingegangen, wie es zum Verständnis der folgenden Abschnitte nötig ist.

fork() erzeugt einen Kindprozeß, der ein vollständiges Abbild des Elternprozesses ist und der beim gleichen Stand des Befehlszählers fortgesetzt wird. Eltern- und Kindprozeß wird jedoch die Möglichkeit geboten, festzustellen, ob es sich um Eltern- oder Kindprozeß handelt: Der Kindprozeß bekommt als Rückgabewert 0, der Elternprozeß die PID des Kindprozesses. Durch bedingte Verzweigung nach dem Schema (".. if Elternprozeß then ... else ...") können beide Prozesse dann unterschiedlich weiterarbeiten.

Einzelschritte beim Aufruf von fork():

  1. Prozeßtabelle überprüfen (Platz frei?)
  2. Speicher für Kindp. allokieren
  3. Elternprozeß-Speicher --> Kindprozeß-Speicher kopieren
  4. Prozeßtabelleneintrag es Elternprozesses aktualisieren
  5. PID für Kindp. wählen, Kindp. in Prozeßtabelle eintragen
  6. Kernel und Dateisystem über Kindprozeß informieren
  7. Fertigmeldung an Eltern- und Kindprozeß senden

wait() ermöglicht dem Elternprozeß das Warten auf die Beendigung des/der Kindprozess(e). Der Elternprozeß wird verdrängt und erst durch das Ende eines Kindprozesses wieder "aufgeweckt". Zur Unterscheidung mehrerer Kindprozesse liefert die Funktion wait() die PID des "gestorbenen" Kindprozesses zurück.

Gibt es keinen Kindprozeß, ist das Ergebnis -1. Beheben des Waisenkind/Zombie-Problems:

Bei exec() wird der ursprüngliche Prozeß durch einen neuen Prozeß ersetzt (eine Rückkehr zum aufrufenden Prozeß ist daher logischerweise nicht möglich). exec() ist der komplizierteste Aufruf, da der komplette Prozeßadreßraum ersetzt werden muß. Dieser Aufruf ist auch als Kommando verfügbar (exec [Programmname]). Der Ablauf im Schema:

  1. Zugriffsrechte prüfen (Datei ausführbar?)
  2. Größe der Speichersegmente feststellen
  3. Aufrufparameter und Umgebung des Aufrufers festhalten
  4. Speicher des Aufrufers freigeben, neuen Speicher allokieren
  5. Neues Programm in den Speicher laden
  6. UID-, GID-Bits bearbeiten
  7. Prozeßtabelle aktualisieren
  8. Bereitmeldung an den Kernel senden

    Schließlich gibt es noch eine Systemfunktion, welche die zeitweise Blockierung eines Prozesses erzwingt: Mit sleep() kann ein Prozeß für eine definierte Zeit "eingeschläfert" werden. Nach Ablauf der vorgegebenen Zeit, wird der Prozeß wieder auf "bereit" gesetzt und kann weiterlaufen. Auch sleep() ist als Kommando verfügbar (sleep [Zeit in Sekunden]).

    1.6.6 Die Programme init und getty

    Nach dem Start des Rechners und Laden von UNIX starten als erstes:

    Alle Prozesse, die auf dem Rechner laufen sind Kindprozesse von init (wobei "Kind" hier auch für alle weiteren Nachkömmlinge steht). Im Single-User-Modus werden von init nur noch einige Prozesse gestartet, im Multi-User-Modus sind wesentlich mehr Prozesse zu aktivieren (z. B. der Drucker-Spooler, die Abrechnung, etc.). Alle zu startenden Prozesse sind in der Datei /etc/inittab aufgeführt. init holt sich die Informationen über zu startende Prozesse aus der Datei /etc/inittab. Für uns ist eigentlich nur das Programm getty interessant, den dieses Programm sorgt für den Kontakt mit den Terminals. Was geschieht nun weiter?

    1.6.7 Vorbemerkung zur Shell

    Der Kommandointerpreter heißt bei UNIX 'Shell' (er umgibt das System wie eine Schale die Muschel). Die Shell ist sehr leistungsfähig und man kann über eine eigene Programmiersprache Kommandoprozeduren, sogenannte Shell-scripts, erstellen, die sich wie Programme aufrufen lassen. Darauf wird später noch genau eingegangen. Zunächst geht es um die grundlegenden Funktionen. Dabei ist immer von der StandardShell, der Bourne-Shell die Rede. Analoges gilt auch für andere Shells (bash = bourne again Shell, C-Shell, Korn-Shell); es werden dort aber teilweise andere Startdateien verwendet.

    1.6.8 Einflußnahme des Benutzers auf Prozesse

    Alles wird später im Detail behandelt!

    1.7 Grundlagen der Benutzerverwaltung

    Die Benutzerverwaltung ist bei UNIX ebenso offen aufgebaut, wie der Rest des Systems. Es existieren zwei Text-Dateien, die sämtliche Benutzerinformation aufnehmen:

    Beim Login (und beim Wechsel des Benutzerkennzeichens während einer Terminalsitzung) wird auf diese Dateien zugegriffen - sie sind übrigens für alle Benutzer lesbar. Schreiben darf jedoch nur der Superuser und das Programm passwd. Da passwd von jedem Benutzer aufgerufen werden kann, ergibt sich hier eigentlich ein Widerspruch. Gelöst wird das Problem durch das UID-Bit von passwd: während das Programm läuft, nimmt der Prozeß die Identität seines Eigentümers an - und der darf schreiben. Anmerkung: Ab der UNIX-Version System V, Version 3 steht das Paßwort nicht mehr in /etc/passwd, sondern in einer eigenen Datei /etc/shadow. Da /etc/passwd für alle lesbar sein muß (z. B. für die Anzeige des Benutzernamens im ls-Kommando), kann man mit entsprechenden Programmen versuchen, die Paßwörter zu 'knacken'. Durch die Verlagerung der Paßwortinfo in /etc/shadow, die nur von Superuser-Prozessen gelesen werden kann, wird diese Sicherheitslücke geschlossen.

    1.7.1 Was geschieht beim Login?

    Wichtig: Das Paßwort ist in der Datei /etc/passwd verschlüsselt gespeichert. Die Verschlüsselung erfolgt beim Ändern des Passworts mit dem Programm passwd oder bei der Eingabe im Login-Programm. Verglichen werden immer nur die verschlüsselten Passwörter. Auch der Superuser kann das Paßwort nicht entschlüsseln. Wenn Sie Ihr Paßwort vergessen haben, kann er nur ihr altes Paßwort löschen, damit Sie dann ein neues eintragen können. Um das "knacken" von Login-Name und Paßwort zu erschweren, fragt das Login-Programm auch dann das Paßwort ab, wenn schon der Benutzername falsch war. Außerdem wird beim Eingeben des Passworts nichts auf dem Bildschirm angezeigt.

    1.7.2 Aufbau der Datei /etc/passwd

    Die Datei ist eine normale Textdatei und sie enthält für jeden Benutzer genau eine Zeile mit 7 Feldern, die jeweils durch einen Doppelpunkt voneinander getrennt sind. Die Zeilenlänge darf 511 Zeichen nicht überschreiten, wobei die Länge der einzelnen Felder variabel ist. Der Aufbau der Zeile ist:

    Login-Name:Paßwort:UID:GID:Kommentar:Home-Directory:Programm

    Beispiel für einen Eintrag in /etc/passwd:

    karl:,..:235:100:Karl Müller:/usr/karl:/bin/sh

    Gültigkeitsdauer des Paßworts:

    Die Gültigkeitsdauer des Paßworts wird im Paßwortfeld durch Anfügen von Komma und zwei Zeichen vom Superuser eingeschränkt. Bei Verwendung der Shadow-Datei stehen diese Angaben dort.

    Die Zeitdauer wird in Wochen gezählt; der Punkt "." bedeutet 0 Wochen, der Schrägstrich "/" 1 Woche, dann folgen Ziffern und Buchstaben:

  9. 0..9: 2 bis 11 Wochen
  10. A..Z: 12 bis 37 Wochen
  11. a..z: 38 bis 63 Wochen

    Sonderfälle:

    1.7.3 Aufbau der Datei /etc/group

    Auch diese Datei kann von den Benutzern nur gelesen werden, das Schreiben ist dem Superuser vorbehalten. Sie legt die Gruppenzugehörigkeit der Benutzer fest. Die Datei besteht aus Textzeilen mit 4 Feldern, die durch Doppelpunkte getrennt sind:

    Gruppenname:Paßwort:GID:Benutzernamen

    Beispiel für einen Eintrag in /etc/group:

    dozenten::200:kristl,plate,rother,ries,thomas

    1.7.4 Aufbau der Datei /etc/shadow

    Diese Datei kann von den Benutzern nicht gelesen werden, das Lesen und Schreiben ist dem Superuser vorbehalten. Sie enthält das Benutzerpaßwort und Angaben über die Gültigkeitsdauer von Paßwort und Benutzeraccount. Die Datei besteht aus Textzeilen mit 9 Feldern, die durch Doppelpunkte getrennt sind:

    Name:Paßwort:letzte Änderung:Min:Max:Vorwarnzeit:Inaktiv:Verfall:Kennzeichen

    1.7.5 Voreinstellungsverzeichnis /etc/default

    In diesem Verzeichnis werden unter UNIX V.4 die Standardwerte für verschiedene Programme abgelegt. Das Verzeichnis enthält Dateien, deren Namen sich auf das zugehörige Programm oder die zugehörige Funktion des Betriebssystems beziehen, z. B. "passwd", "tar", "boot", "init", etc. Die Einträge in den Daten bestehen in der Regel aus Zeilen mit jeweils einer Zuweisung der Form 'Schlüsselwort'='Wert'. Dazu ein Beispiel:

    /etc/default/passwd:
    Standardwerte für das Paßwort und seine Gültigkeitsdauer. Einige wichtige Werte sind:

    1.7.6 Anlegen eines Benutzers

    Erstaunlicherweise gab es ursprünglich kein Programm zum Anlegen von Benutzern - bei den meisten Systemen hat sich jedoch der Systemverwalter (= Superuser) ein Shell-script dafür angelegt. Bei vielen Systemen wird heute ein Standard-Tool mitgeliefert ('useradd' oder 'adduser'). Anmerkung: In diesem Abschnitt werden einige Kommandos erwähnt, die erst zu einem späteren Zeitpunkt näher erläutert werden. Um einen Benutzer neu einzutragen sind folgende Schritte notwendig: In der Regel wird das Anlegen und Löschen eines Users durch passende Systemprogramme oder -Skripten erledigt.

    Einen Benutzer sperren

    Soll ein Benutzer zeitweise (z. B. bei längerem Urlaub) oder auf Dauer gesperrt werden, seine Dateien aber noch erhalten bleiben, trägt der Superuser im Paßwortfeld einen Zeichenfolge ein, die als Ergebnis der Verschlüsselung nicht vorkommen kann, z. B. '*LCK*'. Überprüfung von /etc/passwd und /etc/group.

    1.7.7 Löschen eines Benutzers

    Die hierfür notwendigen Schritte sind wesentlich gefährlicher, da hier u. U. wichtige Informationen gelöscht werden. In der Regel wird der Benutzer zunächst deaktiviert (er kann sich also nicht mehr einloggen) und erst nach einer gewissen Zeit vollständig gelöscht. Dazu sind dann folgende Schritte nötig:

    Um alle Dateien (nicht Directories) eines Benutzers zu löschen, kann das Kommando find (siehe später) verwendet werden (für UID wird die User-ID des Benutzers eingesetzt):

    find / -user UID -type f -exec rm -f {} ";"

    Probleme können durch Dateien des zu löschenden Benutzers verursacht werden, auf die andere Benutzer ein Link gesetzt haben. Man kann diese Dateien z. B. den betroffenen Benutzern zuordnen.

    1.8 Starten und Stoppen des Systems

    Wie schon anfangs gesagt, sind Start (Bootstrap) und Stop (Shutdown) des Systems bei UNIX wesentlich komplexer, als bei einfachen Betriebssystemen. Es gibt - abhängig von den jeweiligen Aufgaben - mehrere "Run-levels" des Systems; hier nur eine Auswahl:

    0Power-Down: Ausschalten des Rechners
    1Administrativer Level: z. B. Einrichten neu eingebauter Platten oder andere Hardware-Initialisierungen. Oft auch "s" oder "S" (Singleuser = Einzelbenutzer-Modus).
    2Multiuser-Modus ohne Netzwerkanbindung
    33 Multiuser-Modus mit Netzwerkanbindung (Normal-Level)
    4Frei für benutzerdefinierten Modus
    5Firmware-Modus: z. B. Diagnose und Wartung; oft nur mit spezieller Floppy zu starten
    6 Shutdown und Reboot: Wechsel zu Level 0 und dann sofortiges Hochlaufen

    Die Zuordnung der Level kann auch von der oben angeführten abweichen. Der Wechsel des Levels wird durch spezielle Kommandos erreicht, z. B. shutdown, telinit, (re)boot oder halt. So ist beispielsweise auch ein Bootstrap von einem bestimmten Datenträger (Floppy, CD-ROM, ...) möglich.

    Beispiel: Reboot des Systems nach 2 Minuten (Solaris): shutdown -g120 -i6 -y Shutdown sendet eine Nachricht an alle eingeloggten Benutzer, bevor der eigentliche Prozess beginnt. Egal, ob der Reboot-Vorgang durch shutdown oder durch Einschalten des Rechners ausgelöst wurde, sind die Systemaktivitäten im Prinzip immer gleich:

    Diese doch relativ komplexen Aktionen werden wieder über spezielle Shell-Scripts gesteuert. Bei BSD-Unix war der Aufbau dieser Scripts relativ einfach. Die Datei /etc/rc enthält alle beim Systemstart auszuführenden Kommandos. Innerhalb von rc werden eventuell weitere rc-Dateien aufgerufen, z. B.:

    /etc/rc.localStart lokaler Software
    /etc/rc.netStart der Netzwerksoftware
    /etc/rc.singleStart im Single-User-Modus

    Später wurde das System dahingehend erweitert, daß es für jeden Runlevel eine eigene rc-Datei gab (rc0, rc1, rc2, usw.). Ab System V ist das System der rc-Dateien vereinheitlicht worden. Für jeden Runlevel exisitiert eine rc-Datei (rc0, rc1, rc2, etc.) und ein Verzeichnis unter /etc, wobei der Name der Verzeichnisse einheitlich /etc/rcü.d ist (ü steht für den Runlevel, es gibt also rc0.d, rcs.d, rc2.d, usw.). Im Verzeichnis /etc/init.d (manchmal auch /sbin/init.d) sind alle Programme (oder Shell-Scripts) gespeichert, die beim System-Boot aufgerufen werden könnten. In den Verzeichnissen rc.d sind nun nur noch Links auf diese Programme enthalten. Alle Links folgen ebenfalls einer festen Namenskonvention:

    Die so entstandenen rc-Scripts werden in lexikalischer Reihenfolge aufgerufen und zwar zuerst die K-Dateien, dann die S-Dateien. Die Zahl im Namen legt also die Reihenfolge innerhalb der K- oder S-Gruppe fest. Die K-Dateien dienen zum Löschen (Kill) von Prozessen, die S-Dateien zum Starten von Prozessen. Angenommen, es existieren folgende Dateien in /etc/rc.d:

    Dann ist die Aufruf-Reihenfolge:

    K30tcp K40nfs S20sysetup S30tcp S40nfs S75cron S85lp

    Dabei sind K-und S-Dateien mit ansonsten gleichem Namen lediglich Hinweise darauf, dasselbe Programm aufzurufen. So wird z. B. bei den Dateien K30tcp und S30tcp das Programm oder Script /etc/init.d/tcp einmal mit dem Parameter "stop" und einmal mit dem Parameter "start" aufgerufen. Man kann also durch Anlegen von Links das Hochfahren des Systems sehr gezielt steuern. Das entsprechende rc-Script wird dann auch sehr einfach, es läßt sich folgendermaßen skizzieren:

    #!/bin/sh
    # Wenn Directory /etc/rc2.d vorhanden ist
    if [ -d /etc/rc2.d] ; then
    # K-Files bearbeiten
    for f in /etc/rc2.d/K* ; do
       if [ -s $f ]; then
       /bin/sh $f stop
      fi
    done
     # S-Files bearbeiten
    for f in /etc/rc2.d/S*; do
      if [ -s $f ] ; then
      /bin/sh $f start
    fi
     done
    fi
    

    Ein von der rc-Datei aufgerufenens Script in /etc/init.d könnte dann z. B. so aussehen:

    #!/bin/sh 
    case $1 in 
      'start')
      # aufgerufen als "Kxxcron"
      # Lockfilelöschen
      rm -f /var/spool/cron/FIFO
      if [ -x /etc/cron ] ; then
        /etc/cron
      fi
     ;;
     'stop')
     # aufgerufen als "Sxxcron"
     pid=`/bin/ps -e | grep 'cron$' | sed -e 's/^ *//' -e 's/ .*//'`
     if [ "$pid" != "" ] ; then
       /bin/kill -9 $pid
     fi
    ;;
    esac
    

    1.9 Sicherheitsmaßnahmen bei Arbeiten mit Root-Rechten

    Grundsätzlich sollten nur diejenigen Arbeiten mit Superuser-Rechten vorgenommen werden, die wirklich Root-Rechte benötigen. Da 'Root' wirklich alles darf, können Fehler massive Probleme bringen (z. B. das Löschen von Dateien oder das Ändern von Zugriffsrechten). Alle anderen Arbeiten können als 'Normaluser' oder mit Privilegien durch besondere Gruppenrechte durchgeführt werden. Durch Setzen von Gruppenrechten können auch bestimmte Benutzer mit Administrativen Aufgaben für bestimmte Bereiche betraut werden. Anmerkung: Durch die Vergabe von Gruppenrechten kann man sogar bestimmte Benutzergruppen "aussperren". Man ordnet den Benutzern und den zu vor ihnen zu schützenden Verzeichnissen und Dateien dieselbe Gruppe zu. Danach nimmt man bei den Dateien und Verzeichnisse die Gruppenzugriffsrechte weg. Bei Änderungen an "lebenswichtigen" Dateien, zu denen auch die oben genannten gehören, sollte man noch einen Superuser-Login auf einen zweiten Terminal haben laufen haben. Nach den Änderungen wird dann getestet, ob beim root-Login noch alles in Ordnung ist. Im Notfall kann man dann vom zweiten Terminal aus eingreifen. Auch hier gilt grundsätzlich, daß man sich sicher darüber sein sollte, was man eigentlich tut. Von zu verändernden Dateien werden zunächst Sicherheitskopien angefertigt. Bei Shell-Scripts und Konfigurationsdateien kann man vor dem Ändern einzelner Zeilen die betreffenden Zeilen zuerst kopieren und dann die "alte" Version der Zeile durch eine Kommentar-Markierung deaktivieren (bei UNIX sind alle Zeilen, die mit '#' beginnen, Kommantare). Das gilt auch für zu löschende Einträge, die ebenfalls "auskommentiert" werden. So kann man leicht zum alten Stand zurückkehren, wenn nach der Änderung etwas nicht klappt. Als Systemadministrator sollte man auch ein Tagebuch führen. Das kann ein einfaches Heft sein, in das man einträgt, was wann geändert wurde. Manche Fehler zeigen sich erst später und nur auf sein Gedächtnis sollte man sich nicht verlassen.

    Das X Window System

    Der Name

    Fast jeder sagt "X-Windows", dieser Name ist jedoch nicht korrekt. Das X Consortium hat die folgenden Namen als richtig festgelegt:

    Das X Window System

    X begann als Protokollspezifikation. Nachdem vor einigen Jahren immer schnellere Rechner mit Bitmap-Grafikdisplays erhältlich waren, ging das MIT mit der Unterstützung von einigen Firmen (dem X Consortium) daran, das Windowsystem für die Zukunft zu spezifizieren. Es wurde dabei zuerst ein Protokoll festgelegt. Danach begann das MIT mit einer Beispielimplementierung des Protokolls, um zu zeigen, wie es funktioniert und welche Möglichkeiten es bietet. Nach einigen Jahren begannen dann Firmen mit dem Vertrieb von kommerziellen Implementierungen des X Protokolls.

    Da das Protokoll allerdings recht aufwendig war - es teilt sich der Klarheit wegen in mehrere streng getrennte Schichten - waren die anfänglichen Implementierungen relativ langsam. Wesentlich langsamer jedenfalls als solche Windowsysteme, die direkt auf das Bitmap-Display zugreifen. Es folgten dann immer mehr Programme, die auf dem X Window System aufbauen.

    Das X Window System ist jedoch keine einheitliche Benutzeroberfläche, die ein bestimmtes "Look-and-Feel" bietet. X könnte aussehen wie der Macintosh Finder oder wie Microsoft Windows. Dieses deshalb, weil das X-Protokoll sehr einfach ist. Man kann lediglich grafische Elemente (Linien, Kreise, etc.) und Buchstaben auf dem Bildschirm anzeigen. Das Protokoll enthält keine komplexeren Grafikelemente wie Buttons oder Menus. Deshalb gibt es auch keine Aussagen über Aussehen von Anwendungsprogrammen (Style Guide), so daß sich mehrere Standards gebildet haben.

    Möchte man zum Beispiel einen Knopf (Button) mit einer Aufschrift, so muß dieser aus Linien und Text selbst zusammengesetzt werden. Dies kann dem Programmierer aber auch durch ein Toolkit abgenommen werden. Diese Toolkits bestimmen dann hauptsächlich das Look-and-Feel.

    Komponenten von X

    X benötigt hardwareseitig ein Bitmap-Display, eine Tastatur und ein Pointing-Device (Maus, Grafiktablett, etc.)

    Das Pointing-Device muß nur zum Zeigen auf Punkte fähig sein. Es könnte zum Beispiel auch ein Touch-Screen sein. Oder eine Maus mit nur einer Taste. Soll ein Programm konform zur X-Spezifikation sein, müssen alle Funktionen mit nur einer Maustaste ausführbar sein. Dies kann man z. B. erreichen, indem man beim Drücken der Maustaste auch noch gleichzeitig gedrückte Tasten (Control, Meta, etc.) abfragt.

    Softwareseitig gibt es folgende Prozesse:
    X Server Der X-Server ist das Programm, das alle Bildschirmausgaben übernimmt und alle Eingaben von der Tastatur und der Maus verarbeitet. Daher ist ein Teil des X-Servers sehr an die Hardware des Rechners gebunden (Farb- oder Schwarzweiß-Bildschirm, Art der Tastatur, Anzahl der Maustasten, Bildschirmgröße ...). Ein Programm, das etwas auf dem Bildschirm ausgeben will, schickt einen diesbezüglichen Auftrag an den X-Server, der daraufhin eine Linie zeichnet, einen Text ausgibt oder tut, was immer das Programm von ihm verlangt. In der anderen Richtung gibt der X-Server Meldungen an die X-Clients, wann immer der Benutzer eine Eingabe getätigt hat, sei es das Bewegen der Maus, das Drücken einer Maustaste oder eine Eingabe über die Tastatur. Die Programme können dann entscheiden, was sie mit dieser Eingabe anfangen und wie (oder ob überhaupt) sie darauf reagieren. Vorteil dieser Konfiguration ist, daß nur der X-Server über die Möglichkeiten der vorhandenen Hardware informiert sein muß. Die Clients können diese Information vom Server erfragen, wenn sie sie brauchen, müssen sich ansonsten aber nicht darum kümmern.

    Zur Verdeutlichung noch ein Hinweis: bei den meisten anderen Client-Server Systemen (beispielsweise Datenbanksystem, Mailsystem usw.) befindet sich der Client näher am Benutzer als der Server. Bei X ist das naturgemäß umgekehrt, da der Server Tastatur und Bildschirm verwaltet und den Clients zur Verfügung stellt.

    X Clients Jedes Programm, das auf einem X-Bildschirm ein Fenster darstellen will, ist ein X-Client. Der X-Client bittet den Server, gewisse Aufgaben (eben das Zeichnen des Fensters) für ihn zu übernehmen. Sie müssen dazu Aufträge im X Protokoll an den Server schicken.
    Window-Manager Ein Client hat den anderen gegenüber einen gewissen Sonderstatus: der Window-Manager, hier heißt er ctwm. Er stellt dem Benutzer Mittel zur Verfügung, mit deren Hilfe dieser das Aussehen seiner Benutzeroberfläche bestimmen kann. Insbesondere kann der Window-Manager die Größe und die Position der Fenster anderer Clients beeinflussen. Die Clients können dem Window-Manager Hinweise geben, wo und in welcher Größe sie ihre Fenster plaziert haben wollen. Der Window-Manager muß diese Hinweise zwar nicht berücksichtigen, die meisten gängigen Systeme tun dies aber. Durch die Funktion des Window-Managers ergibt sich, daß es zumindest problematisch ist, zwei Window-Manager für einen Bildschirm zu starten. Daher prüfen Window-Manager beim Start in der Regel, ob bereits ein anderer Window-Manager für den Bildschirm existiert und brechen in diesem Fall die Arbeit ab.

    Die Rahmen und Titelbalken, die die einzelnen Fenster verzieren, sind nicht Teil des jeweiligen Clients, sondern werden vom Windowmanager um die Fenster herumgezeichnet, damit durch ihre Betätigung Funktionen des Windowmanagers ausgelöst werden können. Der Windowmanager bestimmt somit auch "look-and-feel" der Benutzeroberfläche. Beachten Sie aber, daß der Window-Manager aber auch nur ein Clientprozeß ist. Es gibt alle möglichen Window-Manager:
    vtwmVirtual twm (virtueller Screen mit Window)
    gwmGeneric Window Manager (gut konfigurierbar)
    olwmOPEN LOOK Window Manager
    mwmMotif Window Manager
    ...Und viele andere

    Was ist das Besondere an X?

    X ist ein portables Windowsystem. X benötigt nur Benutzerprozeße und keine Veränderungen am Betriebssystemkern. X-Server gibt es auch auf anderen Betriebssystemen (MS-DOS, MacOS, Atari TOS, Windows etc.) und es gibt sogenannte X-Terminals, intelligente Grafikterminals, die einen integrierten X Server haben.

    X ist netzwerkfähig. Clients können ihre Grafikausgabe auch auf Server machen, die auf anderen Rechnern im Netz laufen. Als Netzwerkprotokolle können dabei verschiedene Protokolle eingesetzt werden. Bei Unix ist dies meist TCP/IP.

    Wie benutzt man X über ein Netzwerk

    Das X Protokoll unterstützt ja auch Rechner, die vernetzt sind. Das bedeutet, man kann Ausgaben von einem Client auf Rechner A auch auf einem Server auf Rechner B ausgeben. Dafür ist folgendes notwendig:

    Auf dem Zielrechner muß dem Server mitgeteilt werden, daß er Requests vom Senderechner zulassen darf. Das geschieht mit dem Kommando:

       xhost +senderechner
    
    Auf dem Senderechner muß man dem Client mitteilen, daß die Ausgabe nicht auf dem eigenen Display erscheinen soll, sondern beim Zielrechner. Dazu setzt man entweder die Environment-Variable
       export DISPLAY=zielrechner:0
    
    oder man schreibt beim Aufruf des Programms
       clientprogramm -display zielrechner:0
    
    Die Zahl hinter dem Rechnernamen gibt die Nummer des Displays an. Sie kann auch eine Nachkommastelle haben, z.B. 0.1. Normalerweise haben aber die Rechner nur ein Display mit der Nummer 0.

    Die X Session

    Entweder sofort nach dem Einloggen oder durch das Kommando startx wird für den Benutzer eine Session gestartet. Dabei werden automatisch verschiedene Clients gestartet (xterm, twm, xclock, etc.). Die Session beendet sich, wenn der Windowmanager beendet wird.

    Der Mechanismus funktioniert folgendermaßen: von Systemprozessen wird eine Prozedur aufgerufen, welche die Session steuert. Wenn sich die Prozedur beendet, übernehmen wieder die Systemprozesse die Steuerung.

      process xdm is
        while (true)
        do
          xlogin;
          if (Benutzer hat eigene Session-Prozedur)
            then fuehre Benutzer-Session-Prozedur aus
            else if (Benutzer hat zusätzliche Session-Prozedur)
                   then fuehre zusätzliche Session-Prozedur im Hintergrund aus
                 fi;
                 starte xterm im Hintergrund;
                 starte xclock im Hintergrund;
                 starte twm;
          fi
        done
      endprocess
    
    Bei xdm heißt die Benutzer-Session-Prozedur .xsession und die zusätzliche Session-Prozedur .xsession+. Man sollte darauf achten, daß diese Dateien ausführbar sind. Außerdem wird die Session beendet, wenn sich die Prozedur beendet. In der Prozedur sollten also alle Kommandos im Hintergrund gestartet werden, außer dem letzten, das während der gesamten Session laufen muß. Dies ist meist der Window-Manager. Wird dieser dann mit Exit beendet, wird auch die Session mit allen anderen Clients beendet.

    Resourcen

    X-Clients können durch Resourcen parametrisiert werden. Clients besitzen Variablen, die zur Kommunikation zwischen Clients dienen. Diese sind die sogenannten Properties. Eine spezielle Property des Servers sind die Resources. In ihnen sind Parameter gespeichert, welche Clients abfragen können. Resourcen sind zum Beispiel geometry oder font.

    Resourcen sind hierarchisch aufgebaut. Jedes Programm greift auf eine Klasse von Resourcen zu (xterm zum Beispiel auf Xterm). Darunter können sich Komponenten des Programms befinden und am Ende der Hierarchie stehen Eigenschaften. Teile der Hierarchie können auch durch Wildcards ('*') ersetzt werden. Beispiel:

         xterm*font: 9x15
    
    setzt in allen Komponenten von xterm den gewünschten Font auf 9x15. Resourcen werden vom System vorbesetzt. Man kann sie durch eigene ersetzen (.xresources) oder erweitern (.xresources+).

    X und Sicherheit

    Ein Problem von X ist noch die Sicherheit. Zum Beispiel kommt es vor, daß xterm-Fenster beim Ausloggen nicht geschloßen werden, sondern beim nächsten Benutzer wieder auf dem Bildschirm erscheinen.

    Ein anderes Problem liegt am Konzept des TCP/IP-Protokolls. Da nicht alle Rechnertypen, die am Internet hängen, das Konzept einer Benutzer-ID haben, ist diese auch bei TCP/IP nicht vorgesehen. Auf den X-Server kann also nicht nur der augenblickliche Benutzer der Konsole zugreifen, sondern alle Benutzer des Rechners. Und das in beliebiger Form. Ein anderer Benutzer kann zum Beispiel den gesamten Bildschirminhalt überschreiben.

    Bei jedem Anmelden an einem Rechner generiert das Programm xdm, das die Anmeldemaske zur Verfügung stellt, einen Schlüssel und legt ihn in der Datei .Xauthority im HOME-Verzeichnis des Benutzers ab. Jedes X-Programm, das der Benutzer dann startet, sucht in dieser Datei nach dem Schlüssel und gibt ihn dem Server beim Aufbau der Verbindung an. Nur wenn dieser Schlüssel mit dem übereinstimmt, der beim Login generiert wurde, wird die Verbindung tatsächlich aufgebaut, ansonsten wird der Aufbauversuch vom Server zurückgewiesen. Auf diese Art wird verhindert, daß jeder Benutzer seine Fenster auf den Bildschirm eines anderen Benutzers legen und diesen dadurch bei seiner Arbeit behindern kann. Voraussetzung für die Sicherheit des Systems ist natürlich, daß die Rechte für die Datei .Xauthority richtig gesetzt sind. Nur der Eigentümer der Datei darf dafür das Lese- und Schreibrecht haben, alle anderen Benutzer nicht einmal das Leserecht, da sie sonst den Schlüssel aus der Datei herauslesen könnten.

    X ermöglicht unter anderem jedem Programm, das eine Verbindung zum X-Server aufbauen kann, das Mitlesen von Tastatureingaben, die auf dem Rechner vorgenommen werden. Darunter können natürlich auch Paßworteingaben sein (zum Beispiel bei einem rlogin). Daher darf der Zugriff auf den Server auf keinen Fall unkontrolliert freigegeben werden.

    Der Terminalemulator xterm

    Um Nicht-X-Programme unter X laufen lassen zu können, gibt es den Terminalemulator xterm. Er erzeugt ein Fenster, das sich wie der normale Textbildschirm an einem UNIX-Rechner verhält. Um die Nutzung optimal zu gestalten, können mit dem Aufruf mehrere Optionen eingestellt werden, von denen einige hier aufgeführt werden (Vollständig sind sie in der Manualseite aufgeführt):

    xterm [Optionen]
    oder
    xterm [Optionen] & (als Hintergrundprozeß)

    Optionen:

    Die Datei .xsession

    Diese Datei wird nach dem Anmelden vom System abgearbeitet. Es handelt sich bei ihr um ein Shellscript, das von der Standardshell des Benutzers. Die Sitzung eines Benutzers dauert so lange, bis die Datei .xsession vollständig abgearbeitet wurde. Daraus folgt, daß .xsession mindestens ein Programm nicht als Hintergrundprozeß starten darf. Das Ende dieses Programms stellt dann auch das Ende der Sitzung dar. Es ist sinnvoll, Programmen, die man in .xsession startet, eine Positionsangabe mitzugeben, entweder direkt oder über .Xdefaults. Tut man das nicht, muß man das Fenster jeweils per Hand auf dem Bildschirm positionieren. Das Angeben der Position ist bei vielen Programmen über den Parameter -geometry möglich. Beispiel:

    xterm -geometry 80x25+130+360

    erzeugt ein Terminalfenster mit 80 Spalten und 25 Zeilen, dessen obere linke Ecke an der X-Koordinate 130 und der Y-Koordinate 360 liegt.

    Die Datei .xxxwmrc

    Diese Datei konfiguriert den Window-Manager (wobei "xxx" für den gewählten Window-Manager steht. Dieser stellt er die Menüs zur Verfügung, die erscheinen, wenn man auf dem root-Fenster (dem Bildschirmhintergrund) die mittlere oder die rechte Maustaste drückt. Diese Datei dient dazu, die Benutzeroberfläche frei nach seinen eigenen Wünschen zu gestalten.

    Die Datei .rhosts

    Diese Datei gibt an, wer sich von welchem Rechner aus ohne Angabe eines Paßwortes am Rechner anmelden darf. Damit kann man vermeiden, daß bei jedem Aufruf von rlogin das Paßwort eingegeben werden muß. .rhosts darf nur für den User selbst schreibbar sein. Sie muß jedoch für alle lesbar sein. Jede Zeile in .rhosts muß folgenden Aufbau haben:

    Rechnername [Benutzer]

    Die Datei .Xdefaults

    Viele X-Clients ermöglichen es, ihr Aussehen und ihre Konfiguration mittels sogenannter Ressourcen festzulegen. Ressourcen sind im Grunde nur Wörter oder Zeichenketten, die der X-Server bereithält und die der X-Client bei Bedarf abfragen kann. Meist erkundigt sich der Client beim Server, ob für ihn Ressourcen definiert sind und verwendet diese, falls es welche gibt. Ansonsten benutzt er Standardwerte. Jeder Benutzer kann seine eigenen Ressourcedefinitionen in der Datei .Xdefaults in seinem HOME-Verzeichnis ablegen. Diese wird, falls vorhanden, automatisch beim Anmelden dem X-Server bekanntgemacht.

    Was kann man nun überhaupt mit Ressourcen festlegen? Mit Programmname.geometry wird festgelegt, an welcher Stelle ein Fenster des angegebenen Programms bei dessen Start auf dem Bildschirm erscheinen soll. Die Einträge mit den Endungen background und foreground legen für die entsprechenden Programme Vordergrund- und Hintergrundfarbe fest. iconic bestimmt, ob ein bestimmtes Programm als Icon (true) oder als Fenster (false) gestartet wird.

    Zum Inhaltsverzeichnis Zum nächsten Abschnitt
    Copyright © FH München, FB 04, Prof. Jürgen Plate