# Opvullen van de hiaten

## Analyse

De rootdisk heeft een lange weg afgelegd vanaf het nederige begin als een statisch gelinkte shell. Het deelt nu veel features met de populaire klaar-voor-gebruik zijnde distributies. Het heeft bijvoorbeeld:

- Verscheidene algemene utility's, zoals `cat`, `ls`, enzovoort.

- Opstartscripts die automatisch bestandssystemen controleren en mounten.

- Een elegante manier om het systeem af te sluiten.

- Ondersteuning voor meerdere gebruikers en virtuele terminals.

Als laatste test kunnen we de rootdisk vergelijken met de vereisten van de Filesystem Hierarchy Standard (FHS) voor het root bestandssysteem. (We zullen alles in de `/usr` hiërarchie negeren vanwege de ruimtebeperkingen.) Vergeleken met de FHS vereisten, ontbreken er slechts een paar bestanden in de `/bin` directory. In het bijzonder ontbreken op de rootdisk de volgende opdrachten:

- `more`

- `ps`

- `sed`

In aanvulling op de vereiste opdrachten, zou het fraai zijn om de editor "ed" op te nemen die als een optie door de FHS wordt opgesomd. Het is niet zo robuust als vi of emacs, maar het werkt en het zou nog passen op het kleine root bestandssysteem.

Dus om deze fase van het project te voltooien, moeten we de volgende doelen bewerkstelligen:

- De opdrachten `more`, `ps` en `sed` toevoegen.

- De optionele editor `ed` installeren.

## Ontwerp

### more

Er bestaat een `more` opdracht die met util-linux wordt geleverd, maar het zal voor dit project niet werken. De reden hiervan zijn de library afhankelijkheden en ruimtebeperkingen. De util-linux dat `more` meelevert heeft of de libncursus of libtermcap nodig om te kunnen werken en er is gewoon niet voldoende ruimte op de rootdisk om alles erop te krijgen. Dus voor een opdracht `more` zullen we creatief moeten zijn.

De opdracht `more` wordt gebruikt om een bestand pagina-voor-pagina weer te geven. Het lijkt wat op een `cat` opdracht die elke vijfentwintig regels pauzeert. De basislogica wordt hieronder uiteengezet.

- Lees een regel van het bestand.

- Toon de regel op het scherm.

- Pauzeer zodra 25 regels zijn getoond.

- Loop en doe het nogmaals.

Natuurlijk zijn er een aantal details achterwege gelaten zoals wat te doen als de schermdimensies niet zijn waarop we anticipeerde, maar in z'n totaal is het een duidelijke representatie van wat `more` doet. Gegeven de logica van dit voorbeeldprogramma, zou het niet al te moeilijk moeten zijn om een beknopt shellscript samen te stellen dat de basisfunctionaliteit van `more` emuleert. De BASH(1) manpage en Adv-BASH-Scripting-Guide zullen als referenties dienen.

### Meer device bestanden

Het `more` script zal toegang tot devicebestanden nodig hebben die nog niet op de rootdisk aanwezig zijn. In het bijzonder heeft `more` `stdin`,`stdout` en `stderr` nodig, maar nu we er toch mee bezig zijn, kunnen we net zo goed op andere ontbrekende `/dev` bestanden controleren. De Linux Standard Base vereist dat `null`, `zero` en `tty` aanwezig zijn in de `/dev` directory. Bestanden voor `null` en `tty` bestaan reeds vanuit eerdere fasen in het project, maar we hebben nog wel `/dev/zero` nodig. We kunnen refereren naar `devices.txt` in de `Documentation` directory van de Linux broncode voor major en minor nummers.

### ps, sed & ed

Deze drie packages kunnen worden gevonden door gebruik te maken van dezelfde Internetbronnen als we eerder deden. Het procps package komt tevoorschijn in een Ibiblio LSM zoekactie (http://www.ibiblio.org/pub/linux/) op het trefwoord "ps". De "sed" en "ed" packages zijn te vinden op de GNU ftp server op ftp://ftp.gnu.org.

Zowel "sed" als "ed" packages kenmerken GNU's bekende `configure` script en zijn daarom makkelijk te bouwen. Er is geen `configure` script voor "procps" maar dit maakt het niet al te moeilijk. We kunnen gewoon het bestand `INSTALL` lezen om erachter te komen hoe de diverse configuratie-opties in te stellen. We kunnen één van deze opties gebruiken om de complexiteit in het gebruik en het installeren van libproc te voorkomen. De instelling SHARED=0 maakt `libproc` een geïntegreerd deel van `ps` in plaats van een aparte, gedeelde library.

## Constructie

### Schrijf een "more" script

Maak het volgende script aan met een teksteditor en sla het op als `~/fase/bin/more.sh`

    #!/bin/sh
    #
    # more.sh - emuleert de basisfuncties van de "more" binary zonder
    #           dat hier ncurses of termcap library's voor nodig zijn.
    #
    # Veronderstel dat invoer van STDIN komt, tenzij als opdrachtregelargument
    # een geldig bestand is opgegeven.
    if [ -f "$1" ]; then
      INPUT="$1"
    else
      INPUT="/dev/stdin"
    fi
    #
    # Stel IFS in op een newline. Zie BASH(1) manpage voor details over IFS.
    IFS=$'\n'
    #
    # Als de terminaldimensies niet reeds zijn ingesteld als shellvariabelen,
    # gok dan op 80 x 25.
    if [ "$COLS" = "" ]; then
      COLS=80;
    fi
    if [ "$ROWS" = "" ]; then
      ROWS=25;
    fi
    #
    # Initialiseer de row counter variabele
    ROW_COUNTER=$ROWS
    #
    # Lees één regel tegelijkertijd in van het invoerbestand
    # en toon het op STDOUT totdat het scherm is gevuld.
    # Toon een "Press <Enter>" melding op STDERR en wacht op een
    # toetsaanslag van STDERR. Ga verder tot aan het einde van het invoerbestand.
    # Van elke invoerregel groter dan $COLS tekens in lengte wordt de tekst
    # naar de volgende regel geplaatst en deze tellen als meerdere regels.
    #
    while read -n $COLS LINE_BUFFER; do
      echo "$LINE_BUFFER"
      ROW_COUNTER=$(($ROW_COUNTER - 1))
      if [ $ROW_COUNTER -le 1 ]; then
        echo "Press <ENTER> for next page or <CTRL>+C to quit.">/dev/stderr
        read</dev/stderr
        ROW_COUNTER=$ROWS
      fi
    done<$INPUT
    #
    # einde van more.sh

Maak een symbolische link naar `more` aan

    bash# ln -s more.sh ~/fase/bin/more

### Maak extra devicebestanden aan

    bash# ln -s /proc/self/fd ~/fase/dev/fd
    bash# ln -s fd/0 ~/fase/dev/stdin
    bash# ln -s fd/1 ~/fase/dev/stout
    bash# ln -s fd/2 ~/fase/dev/sterr
    bash# mknod -m644 ~/fase/dev/zero c 1 5

### Installeer procps

    bash# cd /usr/src/procps-2.07
    bash# make SHARED=0 CC="gcc -mcpu=i386"
    bash# cd ps
    bash# cp ps ~/fase/bin

### Installeer sed

    bash# cd /usr/src/sed-3.02
    bash# ./configure --host=i386-pc-linux-gnu
    bash# make
    bash# cd sed
    bash# cp sed ~/fase/bin

### Installeer ed

    bash# cd /usr/src/ed-0.2
    bash# ./configure --host=i386-pc-linux-gnu
    bash# make
    bash# cp ed ~/fase/bin

### Strip binary's om ruimte te besparen

    bash# strip ~/fase/bin/*

### Verzeker je van de juiste permissies

    bash# chown 0:0 ~/fase/bin/*
    bash# chmod -R 755 ~/fase/bin
    bash# chmod 4750 ~/fase/bin/su

### Maak het rootdisk image aan

    bash# cd /
    bash# dd if=/dev/zero of=/dev/ram7 bs=1k count=4096
    bash# mke2fs -m0 /dev/ram7
    bash# mount /dev/ram7 /mnt
    bash# cp -dpR ~/fase/* /mnt
    bash# umount /dev/ram7
    bash# dd if=/dev/ram7 of=~/phase7-image bs=1k
    bash# gzip -9 ~/phase7-image

### Kopieer de image naar diskette

Doe de diskette met het label "rootdisk" in het diskettestation fd0.

    bash# dd if=~/phase7-image.gz of=/dev/fd0 bs=1k

## Implementatie

### Systeemstart

Boot op de gebruikelijke manier vanaf de diskset en log in als root.

### Test het "more" script

Geef de kernelmeldingen weer door de uitvoer van `dmesg` door te geven als invoer voor `more`:

    bash# dmesg | more

Bestudeer het `local_fs` script door `more` met een opdrachtregelargument te gebruiken.

    bash# more /etc/init.d/local_fs

### Gebruik ps om de actieve processen te tonen

Geef de processen weer van de gebruiker die thans is ingelogd.

    bash# ps

Toon alle beschikbare informatie over alle actieve processen.

    bash# ps -ef

### Voer een simpel sed script uit

Gebruik `sed` om een alternatieve versie van `/etc/passwd` weer te geven.

    bash# sed -e "s/Legacy/Old School/" /etc/passwd

Verifieer dat sed de wijzigingen niet permanent aanbracht.

    bash# cat /etc/passwd

### Test de "ed" editor

Gebruik `ed` om de eigenschappen van de gebruiker "daemon" te wijzigen.

    bash# ed -p*
    ed* r /etc/passwd
    ed* %p
    ed* /bin/s/Legacy/Old School/
    ed* %p
    ed* w
    ed* q

Verifieer dat de wijzigingen permanent zijn (tenminste totdat het systeem wordt herstart).

    bash# cat /etc/passwd

### Systeem afsluiten

Sluit het systeem elegant af met de opdracht `shutdown`.