# Automatiseren van de systeemstart & afsluiten van het systeem

## Analyse

De rootdisk uit het laatste hoofdstuk ziet er tamelijk goed uit. Het heeft ongeveer zeventig procent van de opdrachten die het Filesystem Hierarchy Standard (FHS) document vereist voor het root bestandssysteem. Plus dat het opdrachten heeft voor het controleren en mounten van bestandssystemen. Maar zelfs met dit alles is de rootdisk verre van perfect. In de lijst hieronder worden drie dingen uiteengezet die wat verbeteringen kunnen gebruiken als het Pocket Linux systeem het hoofd moet bieden aan de professioneler uitziende distributies.

1. Het systeem vereist thans dat de kernelparameter init=/bin/sh na de LILO-prompt wordt getypt om juist te starten. Op elk ander GNU/Linux systeem wordt dit alleen in een noodsituatie gedaan wanneer het systeem is beschadigd.

2. Het controleren en mounten van het root bestandssysteem moet handmatig worden uitgevoerd door na de shellprompt een script uit te voeren. Onder de meeste moderne besturingssystemen wordt deze functie automatisch afgehandeld als onderdeel van het systeemopstartproces.

3. Het is niet erg elegant met CTRL-ALT-DELETE het systeem af te sluiten. Bestandssystemen zouden moeten worden afgekoppeld met umount en informatie in de cache zou voor het afsluiten naar disk moeten worden geschreven. Ook dit is iets dat de meeste besturingssystemen automatisch afhandelen.

De bovenstaande lijst in aanmerking genomen, zijn de doelen voor deze fase als volgt gedefinieerd:

- Geautomatiseerde opstartreeks.

- Mogelijkheid tot het elegant afsluiten van het systeem.

## Ontwerp

### De nodige utility's vaststellen

We hebben een init daemon nodig om de opstart te automatiseren. We weten dit doordat de Bootdisk-HOWTO en From-Powerup-To-BASH-Prompt HOWTO het beiden vermelden als het eerste te starten programma nadat de kernel is geladen. De laatste HOWTO gaat ook in detail in op het `/etc/inittab` bestand en de organisatie van de opstartscripts. Dit zou van hulp kunnen zijn, aangezien de FHS, de blauwdruk die we tot dusverre hebben gebruikt, geen aanbevelingen doet voor init-scripts.

We zullen ook de opdracht shutdown moeten vinden om aan het tweede doel, het elegant afsluiten van het systeem, te voldoen.

### Verkrijgen van de broncode

Het doorzoeken van de Linux Software Map op Ibiblio op het trefwoord "init" geeft een groot aantal resultaten te zien. Uit de From-Powerup-To-BASH-Prompt-HOWTO weten we echter dat de meeste systemen een initdaemon in de stijl van System V gebruiken. De zoekopdracht beperkend tot het aanvullende trefwoord "System V" geeft veel betere resultaten. Het sysvinit package bevat `init`, `shutdown`, `halt` en `reboot` wat alles is wat we nodig hebben. De versie in het LSM record ziet er tamelijk oud uit, maar er staat een URL in die verwijst naar de primaire site, die waarschijnlijk zal leiden naar de laatste versie.

### Afhankelijkheden controleren

De manpage voor init vermeldt een FIFO genaamd `/dev/initctl` welke nodig is voor `init` om met andere programma's in het sysvinit package te communiceren. We zullen dit bestand voor de goede werking van `init` aan moeten maken.

### Uiteenzetting van opstartscripts

Veel van de populaire GNU/Linux distributies maken gebruik van initscripts in de stijl van System V. Aangezien we gebruik maken van een "sysvinit" daemon, is het zinvol om ook gebruik te maken van scripts in de stijl van System V. De volgende documenten roeren het onderwerp betreffende initscripts in de stijl van System V op één of andere manier aan en ze zullen dienen als referenties bij het bouwen van de scripts voor dit project:

- Het Debian Policy Manual -- online beschikbaar op http://www.debian.org/doc/debian-policy.

- De Linux Standard Base specificatie -- in veel formaten te downloaden vanaf http://www.linuxbase.org/spec/index.shtml.

- Essential System Administration, 3rd Edition door Aeleen Frisch -- beschikbaar bij boekwinkels of direct bij O'Reilly Publishing op http://www.oreilly.com/.

Na een blik te hebben geworpen op één of twee van de bovenstaande referenties zouden we een tamelijk goed beeld moeten hebben hoe het systeeminitialisatieproces in de stijl van System V werkt. We zouden ook kunnen weten wat er nodig is om initscripts in de stijl van System V voor het Pocket Linux project aan te maken. Hieronder staat een beknopte opsomming van wat er moet worden gedaan:

- Maak een `inittab` bestand voor de aanroep van een `rc` met een numeriek argument dat het runlevel aanduidt.

- Schrijf een `rc` script dat het runlevelargument gebruikt om de van toepassing zijnde "K" en "S" scripts uit te voeren.

- Pas het eerder gebouwde `local_fs` script aan dat het start en stop argumenten accepteert.

- Maak nieuwe scripts aan voor het afsluiten en opnieuw opstarten van het systeem.

- Zet /etc/rcN.d directory's op en links naar scripts in /etc/init.d.

Zoals altijd zijn de BASH(1) manpage en de Advanced BASH Scripting Guide erg behulpzaam bij het schrijven en begrijpen van shellscripts.

## Constructie

### Installeer sysvinit utility's

    bash# cd /usr/src/sysvinit-2.84/src
    bash# make clobber
    bash# make CC="gcc -mcpu=i386"
    bash# cp halt init shutdown ~/fase/sbin
    bash# ln -s halt ~/fase/sbin/reboot
    bash# ln -s init ~/fase/sbin/telinit
    bash# mknod ~/fase/dev/initctl p

Omwille van de snelheid slaan we de stappen voor het controleren van libaray's en strippen van binary's over. De library vereisten voor sysvinit zijn erg fundamenteel en de Makefile is geconfigureerd om de binary's automatisch te strippen.

### Maak een /etc/inittab bestand aan

Gebruik een teksteditor om het volgende bestand aan te maken en sla het op als ~/fase/etc/inittab

    # /etc/inittab - init daemon configuratiebestand
    #
    # Standaardrunlevel
    id:1:initdefault:
    #
    # Systeeminitialisatie
    si:S:sysinit:/etc/init.d/rc S
    #
    # Runlevelscripts
    r0:0:wait:/etc/init.d/rc 0
    r1:1:respawn:/bin/sh
    r2:2:wait:/etc/init.d/rc 2
    r3:3:wait:/etc/init.d/rc 3
    r4:4:wait:/etc/init.d/rc 4
    r5:5:wait:/etc/init.d/rc 5
    r6:6:wait:/etc/init.d/rc 6
    #
    # einde van /etc/inittab

### Maak een `/etc/init.d/rc` script aan

Gebruik een teksteditor om het volgende bestand aan te maken en sla het op als `~/fase/etc/init.d/rc`

    #!/bin/sh
    #
    # /etc/init.d/rc - runlevel change script
    #
    PATH=/sbin:/bin
    SCRIPT_DIR="/etc/rc$1.d"
    #
    # Controleer dat de directory rcN.d echt bestaat
    if [ -d $SCRIPT_DIR ]; then
    #
    # Voer als eerste de kill scripts uit.
      for SCRIPT in $SCRIPT_DIR/K*; do
        if [ -x "$SCRIPT" ]; then
          $SCRIPT stop;
        fi;
      done;
    #
    # Doe als laatste de startscripts.
      for SCRIPT in $SCRIPT_DIR/S*; do
        if [ -x $SCRIPT ]; then
          $SCRIPT start;
        fi;
      done;
    fi

Maak het bestand uitvoerbaar.

    bash# chmod +x ~/fase/etc/init.d/rc

### Pas het script /etc/init.d/local_fs aan

Er wordt een case statement toegevoegd om het script afhankelijk van het opgegeven opdrachtregelargument de lokale bestandssystemen te mounten of unmounten. Het oorspronkelijke script staat in het "start" gedeelte van het case statement. Het "stop" gedeelte is nieuw.

    #!/bin/sh
    #
    # local_fs - controleer en mount lokale bestandssystemen
    #
    PATH=/sbin:/bin ; export PATH

    case $1 in

    start)
      echo "Checking local filesystem integrity."
      fsck -ATCp
      if [ $(($?)) -gt $((1)) ]; then
        echo "Filesystem errors still exist!  Manual intervention required."
        /bin/sh
      else
        echo "Remounting / as read-write."
        mount -o remount,rw /
        echo "Mounting local filesystems."
        mount -a
      fi
    ;;

    stop)
      echo "Dismounting local filesystems."
      umount -a
      echo "Remounting / as read-only."
      mount -o remount,rw /
      echo "Flushing disk cache."
      sync
    ;;

    default)
      echo "usage: $0 start|stop";
    ;;

    esac
    #
    # einde van local_fs

### Maak een hostname script aan

Gebruik een teksteditor om het volgende script aan te maken en sla het op als `~/fase/etc/init.d/hostname`

    #!/bin/sh
    #
    # hostname - stel de systeemnaam in op de naam die is
    # opgeslagen in /etc/hostname
    #
    PATH=/sbin:/bin ; export PATH

    echo "Setting hostname."
    if [ -f /etc/hostname ]; then
      hostname $(cat /etc/hostname)
    else
      hostname gnu-linux
    fi
    #
    # einde van hostname

### Maak halt & reboot scripts aan

Gebruik een teksteditor om `~/fase/etc/init.d/halt` zoals hieronder getoond aan te maken.

    #!/bin/sh
    #
    # halt - stop het systeem
    #
    PATH=/sbin:/bin ; export PATH

    echo "Initiating system halt."
    halt
    #
    # einde van /etc/init.d/halt

Maak het volgende script aan het sla het op als `~/fase/etc/init.d/reboot`

    #!/bin/sh
    #
    # reboot - reboot het systeem
    #
    PATH=/sbin:/bin ; export PATH

    echo "Initiating system reboot."
    reboot
    #
    # einde van /etc/init.d/reboot

Maak scriptbestanden uitvoerbaar.

    bash# chmod +x ~/fase/etc/init.d/*

### Maak `rcN.d` directory's en links naar scripts in `/etc/init.d`

    bash# cd ~/fase/etc
    bash# mkdir rc0.d rc1.d rc2.d rc3.d rc4.d rc5.d rc6.d rcS.d
    bash# cd ~/fase/etc/rcS.d
    bash# ln -s ../init.d/proc_fs S10proc_fs
    bash# ln -s ../init.d/local_fs S20local_fs
    bash# ln -s ../init.d/hostname S30hostname
    bash# cd ~/fase/etc/rc0.d
    bash# ln -s ../init.d/local_fs K10local_fs
    bash# ln -s ../init.d/halt K90halt
    bash# cd ~/fase/etc/rc6.d
    bash# ln -s ../init.d/local_fs K10local_fs
    bash# ln -s ../init.d/reboot K90reboot

### Maak het rootdiskimage 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=~/phase5-image bs=1k
    bash# gzip -9 ~/phase5-image

### Kopieer de image naar diskette

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

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

## Implementatie

### Systeemstart

Boot de PC met behulp van de diskette met het label "bootdisk" en druk na de LILO-prompt op Enter. Plaats de recent gemaakte rootdisk in fd0 wanneer dit wordt aangegeven. De uitvoer zou het voorbeeld hieronder moeten weerspiegelen:

    boot: bootdisk
    Loading bootdisk
    Uncompressing Linux... Ok, booting kernel.
    ..
    .. [diverse kernelmeldingen]
    ..
    VFS: Insert root floppy to be loaded into RAM disk and press ENTER
    RAMDISK: Compressed image found at block 0
    VFS: Mounted root (ext2 filesystem) readonly.
    Freeing unused kernel memory: 178k freed
    Checking local filesystem integrity.
    /dev/ram0: clean 105/1024 files 2842/4096 blocks
    Remounting / as read-write.
    Mounting local filesystems.
    Setting the hostname.
    INIT: Entering runlevel: 1
    # _

### Verifieer het succes van de opstartscripts

Gebruik de opdracht `mount` om te controleren of alle lokale bestandssystemen als read-write zijn gemount. De uitvoer zou er ongeveer uit moeten zien als in het voorbeeld hieronder.

    bash# mount
    /dev/root on / type ext2 (rw)
    proc on /proc type proc (rw)

Controleer de hostnaam.

    bash# uname -n
    gnu-linux

### Systeem afsluiten

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

    bash# shutdown -h now

We zouden in de volgende uitvoer van `init` en de scripts te zien moeten krijgen waarmee het systeem wordt afgesloten:

    INIT: Switching to runlevel: 0
    INIT: Sending processes the TERM signal
    Terminated
    INIT: Sending processes the KILL signal
    Dismounting local filesystems.
    Remounting / as read-only.
    Flushing disk cache.
    Initiating system halt.
    System halted.