Unix-1 im Wintersemester 1994/95

2. Übungsblatt

Aufgabe 1  (theoretisch, 1 Punkt)

Wodurch ist die Größe einer Datei im Unix-Filesystem beschränkt?  (Nennt mindestens drei Möglichkeiten!)  Wodurch ist die maximale Anzahl der Dateien beschränkt?

Aufgabe 2  (theoretisch, 2 Punkte)

Wieso sind Hardlinks nur innerhalb eines Filesystems möglich?  Wieso ist das bei Softlinks nicht der Fall?

Aufgabe 3  (theoretisch, 2 Punkte)

Wie kann man in einem C-Programm zu einem bekannten Filedeskriptor die Größe der Datei ermitteln?  Nenne mindestens zwei Möglichkeiten!

Aufgabe 4  (theoretisch, 1 Punkt)

Erläutere den Unterschied (wenn es einen gibt) zwischen einem Filedeskriptor und einem File­Pointer!

Aufgabe 5  (theoretisch, 1 Punkt)

Das Verzeichnis unix1 enthält die Dateien msh und parser.h sowie die Unterverzeichnisse ueb1, ueb2 und ueb3 Wie hoch ist der link count im Inode von unix1 und wie kommt er zustande?

Aufgabe 6  (theoretisch, 3 Punkte)

Eine Festplatte hat durch Erschütterungen einen defekten Block, auf den sie nun nicht mehr zugreifen kann.  Zufällig ist dies genau der erste Block in der Free-List der Datenblöcke des auf der Platte liegenden Filesystems.  Weshalb ist die die Free-List dadurch zerstört?  Beschreibe auf informelle Weise einen Algorithmus, mit dem sich die Free-List wieder rekonstruieren läßt!

Aufgabe 7  (praktisch, 10 Punkte)

Im Laufe dieses Kurses sollt Ihr Euren eigenen Kommandointerpreter schreiben.  In dieser Aufgabe ist der Kommandoparser zu implementieren.  Zu diesem Zweck sind drei getrennte C-Quelldateien parser.c, line.c und als Testumgebung die Datei main.c zu schreiben.

In der Datei line.c soll die Funktion readline() eine Kommandozeile von der Standardeingabe in den ihr übergebenen Puffer mit Hilfe der Funktion getchar() einlesen.  Eine Kommandozeile wird mit der Eingabe von newline abgeschlossen.  Die Funktion readline() hat den Zeiger auf den ihr übergebenen Puffer als Rückgabewert zu liefern.  Bei der Eingabe von end-of-file (^D) ist ein Nullpointer zurückzuliefern.

line.c:
        char *readline (char *buf)
In der Datei parser.c soll die Funktion parseline() eine ihr übergebene Kommandozeile in syntaktische Einheiten (tokens) zerlegen.  Die Funktion parseline() liefert einen Zeiger auf die in der Datei ~unix1/parser.h definierte Struktur als Rückgabewert.  Für jedes Kommando einer Eingabezeile muß ein Objekt der nachfolgenden Struktur alloziiert werden.  Bei wiederholtem Aufruf der Funktion parseline() müssen die zuvor alloziierten Strukturelemente mit der Funktion free() freigegeben werden.  Die Eingabezeile soll auf syntaktische Korrektheit überprüft werden.  Syntaktische Fehler in der Eingabezeile sind durch geeignete Meldungen anzuzeigen.

~unix1/parser.h:

struct kommando { struct kommando *next; /* Zeiger auf das Kommando hinter ";" */ char **token_1; /* Liste der Wörter vor "|" */ int num_tok1; /* Anzahl der Wörter vor "|" */ char **token_2; /* Liste der Wörter hinter "|" */ int num_tok2; /* Anzahl der Wörter hinter "|" */ char *inp_tok; /* Zeiger auf das Wort hinter "<" */ char *out_tok; /* Zeiger auf das Wort hinter ">" */ int is_ampersand; /* "&" in dem Kommando */ int is_pipe; /* "|" in dem Kommando */ };

Die Komponente next der oben angegebenen Struktur verkettet die Kommandos einer Eingabezeile.  Der Nullpointer kennzeichnet das Ende der Verkettung.  Die Zeiger auf die Wörter der Eingabezeile token_1 und token_2 können mit Hilfe der Funktion realloc() den Erfordernissen angepaßt werden.

parser.c:
        struct kommando *parseline (char *buf)
In der Datei main.c ist in der Funktion main() die Testumgebung für die implementierten Module zu schreiben.  Es soll die mit den Funktionen readline() und parseline() eingelesene und interpretierte Eingabezeile sinnvoll ausgegeben werden, d.h. die einzelnen Komponenten der Struktur kommando sind anzuzeigen.  Zu Testzwecken steht Euch in der Datei ~unix1/parser.test ein Testinput zur Verfügung.

Hier zwei kurze Beispiele:

   prompt>  ls  -l   file  |  wc  &  ;  wc -l > x file
   token_1 = "ls", "-l", "file"
   num_tok1 = 3
   token_2 = "wc"
   num_tok2 = 1
   is_pipe = true
   is_amp = true
   
   token_1 = "wc", "-l", "file"
   num_tok1 = 3
   out_tok = "x"
   
   prompt>      ls -l |
   parser: Invalid null command.
   
Vorbild für das, was die Shell noch akzeptiert und die Fehlermeldungen ist die csh(1) Ausnahme: Wenn mehr als eine Pipe auftritt, ist die Meldung ,,Too many pipes'' auszugeben.  Beachtet bitte auch, daß das "&" sowohl die Hintergrundausführung anzeigt als auch Kommandoterminator ist, also ähnlich wie das Semikolon wirkt.

Da diese Aufgabe für C-Anfänger relativ schwierig ist und alle nachfolgenden Aufgaben auf dem Parser aufbauen, wird den Gruppen, die es bis zum Abgabetermin nicht geschafft haben, ein funktionsfähiger Parser von uns als Objectfile zur Verfügung gestellt.  Bewertet wird dann der bis dahin erstellte Lösungsansatz.

Alle von den Modulen definierten, aber nicht exportierten Variablen und Funktionen sind als statisch (static) zu deklarieren, und es ist ein Makefile für die Aufgabe zu erstellen!  Ab jetzt werden praktische Aufgaben nur abgenommen, wenn beide Bedingungen erfüllt sind.