1.6 Allgemeine Skript-Erstellung auf FLI4L

Unterabschnitte

- 1.6.1 Aufbau
- 1.6.2 Umgang mit Konfigurationsvariablen
  - 1.6.2.1 Allgemeines
  - 1.6.2.2 Beispiel für das Ablegen von Werten in einer Datei
  - 1.6.2.3 Beispiel für das Ablegen von Variablen im Config-Dateiformat
- 1.6.3 Fehlersuche
- 1.6.4 Hinweise

# 1.6 Allgemeine Skript-Erstellung auf FLI4L

Hier folgt jetzt keine allgemeine Einführung in Shell-Scripts, das kann jeder im Internet selber nachlesen, es wird nur auf die spezielle Gegebenheiten bei FLI4L eingegangen. Infos dazu gibt es in den Unix-/Linux- Manualpages. Folgende Links können als Einstiegspunkte zu diesem Thema dienen:

- Einführung in Shell-Scripts:
  - http://cip.physik.uni-freiburg.de/main/howtos/sh.php
- Manualpages online:
  - http://www.freebsd.org/cgi/man.cgi?manpath=Red+Hat+Linux/i386+9
  - http://heapsort.de/man2web
  - http://man.he.net/
  - http://www.linuxcommand.org/superman_pages.php

Für Unix-User: Leider war es wegen des begrenzten Platzes nicht möglich, erweierte Tools, wie z.B. awk, tail, uniq, etc. einzubinden. Viele von diesen Tools lassen sich aber mit einfachen Maßnahmen nachbilden

## 1.6.1 Aufbau

In der Unix-Welt ist es nötig, ein Script mit dem Namen des Interpreters zu beginnen, daher steht in der ersten Zeile:

          #!/bin/sh

Damit man später leichter erkennen kann, was ein Script macht und wer es geschrieben hat, sollte jetzt ein kurzer Header folgen, in etwa so:

          #--------------------------------------------------------------------
          # /etc/rc.d/rc500.dummy - start my cool dummy server
          #
          # Creation:     19.07.2001  Tobias Gruetzmacher <fli4l@portfolio16.de>
          # Last Update:  11.11.2001  Tobias Gruetzmacher <fli4l@portfolio16.de>
          #--------------------------------------------------------------------

Nun kann das eigentliche Script folgen...

## 1.6.2 Umgang mit Konfigurationsvariablen

### 1.6.2.1 Allgemeines

Pakete werden über die Datei package/config/package.txt konfiguriert. Die darin enthaltenen Variablen werden beim Erzeugen der Boot-Diskette in die Datei rc.cfg übernommen. Beim Booten des Routers wird diese Datei eingelesen, bevor irgend ein rc Script (scripte unter /etc/rc.d) gestartet wird. Diese Scripte können dadurch auf alle Konfigurationsvariablen einfach durch $CONFIG_VARIABLE zugreifen.

Benötigt man Werte von Konfigurationsvariablen auch nach dem Booten noch, müssen sie separat abgelegt werden, da die rc.cfg Datei nach dem Hochfahren des Routers verschwindet. Üblich ist dabei, die Werte in eine Datei unter /var/run/<name> abzulegen. Von dort kann sie dann ein anderes Script wieder auslesen. Dabei gibt es zwei verschiedene Vorgehensweisen:

- Man schreibt die Werte einfach ein eine Datei und ließt sie nachher unter Beachtung des verwendeten Formats aus.
- Man generiert eine eigene Config-Datei, in der die Variablen in der Form FOO='foo' stehen.

Für beides gibt es im folgenden ein konkretes Beispiel.

### 1.6.2.2 Beispiel für das Ablegen von Werten in einer Datei

Am Beispiel des ISDN-Paketes erklärt, würde das Auswerten der Konfigurationsvariablen so aussehen (/etc/rc.d/rc340.circuits):

            # Laufvariable für % Variablen
            idx=1
            # Ist isdn überhaupt aktiv?
            if [ "$OPT_ISDN" = "yes" ]
            then
            # konfiguriere 1-n circuits
                while [ "$idx" -le "$ISDN_CIRCUITS_N" ]
                do
                    # wie ist denn die Einwahlnummer des n-ten circuits
                    eval eaz='$ISDN_CIRC_'$idx'_EAZ'
                    # und die lokale IP Adresse für das Interface
                    eval local='$ISDN_CIRC_'$idx'_LOCAL'
                    # ... remote
                    eval remote='$ISDN_CIRC_'$idx'_REMOTE'
                    # ... netzmaske
                    eval netmask='$ISDN_CIRC_'$idx'_NETMASK'

Da einige Werte später noch gebraucht werden, werden sie in einer Datei abgelegt:

                    # Datei erzeugen und Wert reinschreiben
                    echo $local >/var/run/$dev.conf
                    # Rest anhängen
                    echo $remote >>/var/run/$dev.conf
                    echo $netmask >>/var/run/$dev.conf

Braucht man die Werte später wieder, liest man sie einfach wieder aus, wie man am Beispiel von /usr/local/bin/delete-all-routes sehen kann:

            # auslesen der abgelegten werte
            conf=`cat /var/run/$dev.conf`
            # die in $conf stehenden Werte werden zu $1, $2, $3, ...
            set $conf
            # Verwenden der Werte
            /sbin/ifconfig $dev $1 pointopoint $2 netmask $3 up

Steht nicht von vornherein fest, wieviele Werte dort drin stehen werden, arbeitet man mit shift, bis keine Variablen mehr da sind. Das könnte wie folgt aussehen:

            # auslesen der abgelegten werte
            conf=`cat /var/run/$interface.conf`
            # die in $conf stehenden Werte werden zu $1, $2, $3, ...
            set $conf
            # Verwenden der Werte
            while [ "$1" != "" ]
            do
                /sbin/route add -net $1 netmask $2 dev $interface
                # die beiden verbrauchten Werte wegwerfen und die nächsten
                # nach vorne holen. Dabei wird in diesem Fall $3 zu $1, $4
                # zu $2, ... , $n zu $(n-2)
                shift 2
            done

### 1.6.2.3 Beispiel für das Ablegen von Variablen im Config-Dateiformat

Möchte man die Variablen im Format der Config-Dateien ablegen, könnte das wir folgt aussehen (am Beispiel von register):

- in /etc/rc.d/rc910.register werden die Config-Variablen in eine Datei geschrieben:

                 {
                      echo "register_server='$REGISTER_SERVER'"
                      echo "register_always='$REGISTER_ALWAYS'"
                 } > var/run/register.conf

- die Werte werden dann in /usr/local/bin/register.sh einfach über das ``source'' Komando der Shell (kurzform ``. filename'') wieder eingelesen und sind dann einfach in der Umgebung des Scripts verfügbar:

                    . /var/run/register.conf

Als Namenskonvention wird hier /var/run/<opt name>.conf festgelegt.

## 1.6.3 Fehlersuche

Bei Start-Scripts ist es oft sinnvoll, diese bei Bedarf im Debug-Modus der Shell laufen zu lassen, um festzustellen, wo ``der Wurm drin ist''. Dazu wird am Anfang und am Ende folgendes eingefügt:

          begin_script <OPT-Name> "start message"
          <script code>
          end_script

Im normalen Betrieb erscheint jetzt beim Start des Scriptes der angegebene Text und am Ende der gleiche Text mit einem vorangestellten ``finished''.

Will man die Scripte debuggen, muß man zwei Dinge tun:

1. Man muß DEBUG_STARTUP auf 'yes' setzen.
2. Man muß das Debuggen für dieses Opt aktivieren. das tut man in der Regel durch den Eintrag

             <OPT-Name>_DO_DEBUG='yes'

   in der Konfigurationsdatei1.2. Jetzt wird während der Ausführung am Bildschirm genau dargestellt, was passiert.

## 1.6.4 Hinweise

- Es ist immer besser, geschweifte Klammern an Stelle von runden Klammern () zu benutzen. Allerdings muß dabei darauf geachtet werden, daß nach der öffnenden Klammer ein Leerzeichen oder eine neue Zeile vor dem nächsten Befehl kommt und vor der schließenden Klammer ein Semikolon oder auch eine neue Zeile kommt. Beispielsweise ist:

              { echo "cpu"; echo "quit"; } | ...

  gleichbedeutend mit:

              {
                      echo "cpu"
                      echo "quit"
              } | ...

- Ein Script kann mit ``exit'' vorzeitig beendet werden. Dies ist aber bei den Start-Scripts (opt/etc/rc.d/*, opt/etc/prep/*), den Stop-Scripts (opt/etc/rc0.d/*) und den ip-up/ip-down-Scripts (opt/etc/ppp/*) geradezu tödlich, da auch nachfolgende Scripts nicht mehr ausgeführt werden. Im Zweifelsfall immer weglassen.

- KISS - Keep it small and simple - Du willst Perl als Script-Sprache verwenden? Dir reichen die Scripting-Möglichkeiten von FLI4L nicht? Überdenke deine Einstellung! Ist dein OPT wirklich nötig? FLI4L ist immer noch ``nur'' ein Router, ein Router sollte eigentlich keine Serverdienste anbieten.

- Die Fehlermeldung ``: not found'' heißt meistens, das das Script noch im DOS-Format vorliegt. Weitere Fehlerquelle: Das Script ist nicht ausführbar. In beiden Fällen sollte das opt/<package>.txt File daraufhin geprüft werden, ob es die Korekten mode/gid/uid/flags optionen enthält bzw. Wenn das Script erst bem Booten erzeugt wurde, ein ``chmod +x <Scriptname>'' ausgeführt werden.

- Für temporäre Dateien sollte der Pfad /tmp genutzt werden. Es ist aber unbedingt darauf zu achten, daß hier nur wenig Platz ist weil dies in der Rootfs-Ramdisk liegt! Wenn mehr Platz benötigt wird, muss man sich eine eigene Ramdisk erstellen und mounten. Details dazu verrät der Abschnitt ``RAM-Disks'' dieser Dev-Doku.

- Damit temporäre Dateien eindeutige Namen erhalten sollte man grundsätzlich die aktuelle Prozess-ID an die Datei anhängen. Ein ``guter'' Dateiname ist also /tmp/<name-des-opts>-$$ statt /tmp/<name-des-opts>, wobei <name-des-opts> natürlich nicht so stehen bleiben soll, sondern ersetzt wird durch...was wohl?

Das Fli4l-Team
23. Februar 2006