Arktur:Entwickler-Dokumentation
Derzeit ist diese Seite eine Kopie der Entwickler-Dokumentation des Eisfair-Projektes. Nach einigen Diskussionen dürfte hier aber bald die "Arktur-Dokumentation für Entwickler" stehen. Sicherheitshalber: im folgenden Text ist meistens nur "Eisfair" durch "Arktur" ersetzt worden, die Verzeichnisstruktur gilt meistens nur für Eisfair, nicht für Arktur.
Grundlagen
Arktur 4 basiert auf einer glibc mit der Versionsnummer 2.3; diese wird von allen modernen Distributionen unterstützt. Daher können die meisten Binaries direkt kopiert und auf Arktur ausgeführt werden.
Falls jemand genauere Informationen zu den betroffenen Distributionen hat, soll er sich bitte melden. Binärdateien von SUSE 9.0 sind ohne Probleme zu benutzen.
Der Umfang der Arktur-Basis-Pakete
Das Base-Package ist recht reichhaltig mit Tools ausgestattet (viel mehr als während der Beta-Versionen); im Normalfall sollte man mit den Programmen, die darin enthalten sind, gut auskommen. Falls allerdings bestimmte Programme von vielen Package-Entwicklern genutzt werden, die nicht im Base-Package enthalten sind, kann über eine Integration in das Base-Package nachgedacht werden. Es sollte auf jeden Fall vermieden werden, dass bestimmte Packages dasselbe Programm enthalten.
Erstellung eines Installationspackages
Ein Installationspaket für Arktur ist im wesentlichen ein mit gzip komprimiertes Tar-Archiv, in dem neben den eigentlichen Dateien des Paketes noch einige weitere Informationen/ Scripts enthalten sein müssen. Diese sind:
Bestandteile | Status |
---|---|
Paket-Info-Datei | zwingend |
Installationsscripts | optional |
Menüs für Setup | optional |
Das Paket selbst spiegelt den Dateibaum ab dem root-Verzeichnis, also ``/ wieder. Eine zu installierende Datei /usr/bin/foo muss also im Tar-Archiv als usr/bin/foo (ohne absoluten Pfad, also relativ!) abgespeichert sein. Als Beispiel denken wir uns ein Paket ``bar, welches als Dienst unter eisfair laufen soll. Der dazughörige Daemon soll ``bard heissen. Ausserdem soll noch eine Konfigurationsdatei etc/bard.conf und eine Shared-Library usr/lib/foo.so.1 dazugehören.
Dokumentation zu diesem Package können wir im Verzeichnis /usr/share/doc/bar ablegen. Dort legen wir die selbstgeschriebene Hilfedatei ``bar.txt ab.
Damit dieser Dienst gestartet wird, braucht man noch eine rc-Datei, welche unter /etc/init.d/bard gespeichert werden soll. Dann sieht der ``Baum im Archiv folgendermaßen aus:
etc/bard.conf Konfiguration etc/init.d/bard rc-Datei usr/sbin/bard Executable als Daemon usr/lib/foo.so.1 Shared Library
Nun zu den zusätzlichen Dateien, welche die Installation/ Administration des Pakete regeln.
Paket-Info-Datei
dev-info-naming Diese Datei ist zwingend, d.h. sie sollte immer im tar-Archiv enthalten sein. Sie muss in var/install/packages liegen und den Namen des Packages haben. Als Package-Name sollten nur die Kleinbuchstaben a-z, die Zahlen 0-9 und der Bindestrich verwendet werden. Eine Versionsnummer sollte nicht mit im Paketnamen enthalten sein, damit man nicht bei Updates plötzlich mehrere verschiedene Packages auf seinem Arktur sieht. Beispiel für Package ``bar: var/install/packages/bar - Dateiname entspricht Paketname!
Der Aufbau dieser Paket-Info-Datei entspricht vollständig dem Format der Info-Datei, die auch für die Paketbeschreibungen zuständig sind.
Installationsscripts
Man kann zwei Installationsskripte im Tar-Archiv unterbringen, nämlich
tmp/preinstall.sh Script vor dem Auspacken tmp/install.sh Script nach dem Auspacken
Diese Scripts sind optional, sie müssen also nicht zwingend vorhanden sein. PACKAGE ist der Paketname, z.B. apache. Das Archiv wird beim Herunterladen im Verzeichnis /tmp gespeichert. Anschließend wird versucht, die Datei tmp/preinstall.sh zu extrahieren. Wenn sie existiert, wird sie anschließend ausgeführt. Der Zweck ist einfach: Hier können vorbereitende Kommandos ausgeführt werden (z.B. Löschen einer alten Version). Anschließend wird das komplette tar-Archiv ausgepackt, und zwar immer vom Root-Verzeichnis ``/ ausgehend, so daß alle Dateien im richtigen Verzeichnis landen. Als letztes wird versucht, die Datei /tmp/install.sh auszuführen, falls sie existiert. Diese kann beim Aktivieren von Services (z.B. unseres bard-Programmes) genutzt werden, hier ein Beispiel:
- !/bin/sh
cd /etc/rc2.d \# in's rc-Verzeichnis, Runlevel 2 ln -sf ../init.d/bard S50bard \# Boot-Script linken ln -sf ../init.d/bard K50bard \# Kill-Script linken
- Menüs für eis-Administration erweitern, s.u.:
/var/install/bin/add-menu \
/var/install/menu/setup.services.menu \ /var/install/bin/setup.services.bard \ ``Foo Services
exit 0
Deinstallation
/var/install/deinstall/<PACKAGE> Das Script muss zwingend vorhanden sein. Seine Aufgabe besteht in der Entfernung aller Paketdateien und der entsprechenden Menüeinträge. Dazu zählen auch:
- Chronjobs
- Systembenutzer
- Benutzergruppen
Sonstige eingefügte Einträge in paketfremden Dateien. Bei der Entfernung von Bibliotheken ist gegebenenfalls eine Abhängigkeitsprüfung zu anderen Paketen durzuführen.
Dokumentation und Changelog
Im Verzeichnis /usr/share/doc/<PACKAGE> ist eine Datei changes.txt anzulegen, in dem die Veränderungen, die von Version zu Version am Paket durchgeführt werden, kurz beschrieben werden.
Bewährt hat sich eine Form wie in folgendem Beispiel:
1.0.6 --> 1.0.7
- added file /bin/bigone - deleted obsolete variable ONE in
/etc/config.d/master
- renamed /etc/old to /etc/new - -
1.0.5 --> 1.0.6
- modified some comments in /etc/this - -
Es sollten also die letzten Änderungen jeweils oben in der Datei changes.txt stehen. Uralte Änderungen können mit der Zeit entfallen.
Die eigentliche Dokumentation soll ebenfalls im Verzeichnis /usr/share/doc/<PACKAGE> abgelegt werden, ebenfalls im Textformat und PACKAGE.txt heissen. Weiteres siehe Dokumentation. Zusätzliche Dokumentation, die den Originalquellen normalerweise beiliegt (man-Pages, README, etc.), sollte nicht mitgeliefert werden.
Menüs für SysAdm
Auch die Menüs sind optional und werden nur für eine spätere Administration benötigt. Das SysAdmin-Menü basiert auf einfachen Shell-Scripts und ist als Übergangslösung gedacht, bis eine komfortable Oberfläche (über Browser bedienbar) zur Verfügung steht. Unter /var/install befinden sich auf dem eisfair-Server folgende Unterverzeichnisse:
bin | Shell-Scripts |
menu | Menü-Dateien |
packages | Paket-Info-Dateien, s.o. |
Die Menü-Dateien haben folgende Struktur:
TITEL | |
---|---|
Kommando | Beschreibung |
Kommando | Beschreibung |
Hier ein Beispiel des Hauptmenüs setup.menu:
EIS/FAIR simple setup /var/install/bin/setup.packages Package administration /var/install/bin/setup.services Service administration /var/install/bin/setup.users User administration
Die Menüs sind hierarchisch. Die Struktur wird durch den Dateinamen klar:
setup.menu Hauptmenü setup.packages.menu Untermenü Packages setup.services.menu Untermenü Services setup.users.menu Untermenü Users
Diese Strukturen kann man beliebig tief führen und auch an gewünschter Stelle erweitern. Der Befehl
/var/install/bin/add-menu \ /var/install/menu/setup.services.menu \ /var/install/bin/setup.services.bard \ ``Foo Services
im Installationsskript erweitert nun das Menü setup.services.menu um eine weitere Zeile, nämlich:
/var/install/bin/setup.services.bard ``Foo Services
Es erscheint also dann unter ``Service administration ein weiterer Menüpunkt ``Foo Services. Das Shell-Script /var/install/bin/setup.services.bard ist einfach ein weiterer Start eines Untermenüs. Es kann z.B. so aussehen:
- ! /bin/sh
/var/install/bin/show-menu \
/var/install/menu/setup.services.bard.menu
Und setup.services.bard.menu folgendermaßen:
Foo administration /var/install/bin/bard-status Show status of inetd /var/install/bin/bard-stop Stop inetd /var/install/bin/bard-start Start inetd
Die 3 Scripts bard-status usw. starten nun keine weiteren Untermenüs, sondern führen dann tatsächlich Funktionen aus. Sie können z.B. so aussehen:
------------------ schnipp ------------------------- #! /bin/sh # bard-status pid=`cat /var/run/bard.pid 2>/dev/null`
status=dead
if [ ``$pid != `` ] then kill -0 \$pid if [ \$? = 0 ] then status=alive fi fi
if [ $status = alive ] then echo ``bard is running else echo ``bard is not running fi echo /var/install/bin/anykey ------------------ schnapp ------------------------- ------------------ schnipp ------------------------- #! /bin/sh # bard-start sh /etc/init.d/bard start echo /var/install/bin/anykey ------------------ schnapp ------------------------- ------------------ schnipp ------------------------- #! /bin/sh # bard-stop sh /etc/init.d/bard stop echo /var/install/bin/anykey ------------------ schnapp -------------------------
Das Shell-Script /var/install/bin/anykey fragt den Benutzer lediglich nach der ENTER-Taste als Bestätigung.
Zusammenfassend noch mal alle Dateien in unserem bard-Package:
Dateiname Funktion etc/bard.conf Konfiguration etc/init.d/bard rc-Datei usr/sbin/bard Executable als Daemon usr/lib/foo.so.1 Shared Library var/install/bin/setup.services.bar Knoten im Menü-Baum var/install/bin/bard-status Blatt im Menü-Baum var/install/bin/bard-stop Blatt im Menü-Baum var/install/bin/bard-start Blatt im Menü-Baum var/install/menu/setup.services.bar.menu Menü-Datei var/install/packages/bar Package-Info-Datei usr/share/doc/bar/bar.txt Dokumentation zum Pacakge usr/share/doc/bar/changes.txt Changelog-Datei
Standardskripte
In der aktuellen Version von Arktur sind folgende Skripte verfügbar, die man benutzen sollte, um Standardfunktionen anzubieten.
/var/install/bin/anykey wartet auf ENTER /var/install/bin/add-group fügt eine neue Gruppe zum System hinzu /var/install/bin/add-menu erstellt einen Menüeintrag für das Setup /var/install/bin/add-user fügt einen neuen Benutzer zum System hinzu /var/install/bin/ask wartet auf Eingabe von y(es) oder n(o) /var/install/bin/check-version überprüft ein Paket auf seine Version /var/install/bin/del-menu entfernt einen Menüeintrag aus dem Setup /var/install/bin/edit startet den Editor zum Editieren der Konfiguration /var/install/bin/remove-user entfernt einen Benutzer vom System
Damit wird vermieden, dass diese Sachen von jedem Paketentwickler neu implementiert werden müssen. Welche Parameter das Skript jeweils erwartet, ist im Skript selbst am Anfang beschrieben.
Konfiguration von Paketen
Die Konfiguration von Paketen kann in der Datei /etc/config.d/PACKAGE festgehalten werden. Die einzelnen Zeilen sollten folgender Notation entsprechen: VARIABLE='Wert'
Kommentare können mit `#' eingeleitet werden. Beispiel für /etc/config.d/inet (Package ``inet)
#--------------------------------------------------- # Configuration of inet package #---------------------------------------------------
START_TELNETD='no' START_FTPD='yes' START_SSH='yes'
Beispiel für /etc/config.d/apache (Package ``apache)
#--------------------------------------------------- # Configuration of apache package #---------------------------------------------------
START_APACHE='yes' DOCUMENT_ROOT='/var/www'
Beispiel für /etc/config.d/mail (Package ``mail, auszugsweise)
#--------------------------------------------------- # Configuration of mail package #---------------------------------------------------
START_POP3='yes' START_IMAP='yes'
POP3IMAP_CREATE_MBX='no'
POP3IMAP_USE_MAILONLY_PASSWORDS='no' POP3IMAP_TRANSPORT='default'
INFO-Datei
Diese Datei soll eine bessere Übersicht über die verfügbaren Pakete und notwendige Verwaltungsdaten bereitstellen.
Hinweis: Die bisherige Info-Datei, die im Package selbst enthalten ist, bleibt erhalten. An ihrem Format ändert sich nichts.
Damit ein späterer Umstieg auf einen XML-Parser möglich ist, bitte die Sonderzeichen, die XML eine Sonderbedeutung haben, entsprechend maskieren oder vermeiden.
Namen und Pfad
Der Info-Datei erhält den Dateinamen des Packages zuzüglich ,,.info``. Sie steht im selben Verzeichnis wie das zugehörige Package.
Beispiel: Wenn der Pfad zum Package ,,slrn.tar.gz`` ,,http://www.meine-domain.de/eisfair/``lautet (also die Adresse das Paketes ,,http://www.meine-domain.de/eisfair/slrn.tar.gz``ist), dann heisst die zugehörige Info-Datei ,,slrn.tar.gz.info``; deren Adresse lautet somit ,,http://www.meine-domain.de/eisfair/slrn.tar.gz.info``.
Format
Die Info-Datei hat eine XML-Struktur, die folgendermassen aussieht:
<package> ... </package>
Innerhalb des Package-Tags sind die unten beschriebenen Tags erlaubt. Die Werte sind, soweit nicht anders gekennzeichnet, Freitext. Werte, die nicht Freitext sind, sind case-sensitiv (auf Groß- und Kleinschreibung achten!). Freitexte dürfen folgende Zeichen nicht enthalten: ``<, ``>,$.
Jedes Tag (bis auf <description>) muss mit Starttag, Wert und Endtag in genau einer Zeile stehen.
<name>
: Der Name des Packages
<short>
: Eine Kurzbeschreibung (max 60 Zeichen)
<version>
: Die Version des Packages; Kein Freitext (siehe unten)
<date>
: Das Releasedatum dieser Version
<author>
: Der Name des Authors, inklusive EMail-Adresse
<status>
: Der Status des Packages (siehe unten); Kein Freitext
<section>
: Der Bereich, dem dieses Package angehört (siehe unten); Kein Freitext URL zur Homepage
<require-package>
: Der Name eines Packages, das zur korrekten Funktion dieses Packages zwingend vorausgesetzt wird
: ...
<description>
: Eine ausführlichere Beschreibung des Programmes, Hinweise, Tips, Patches ...
Die Reihenfolge der Tags ist beliebig. Die Tagnamen müssen in Kleinbuchstaben gesetzt sein. Im folgenden weitere Beschreibungen der Tags.
version
Dieser Wert muss folgendem Schema entsprechen: X.Y.Z, wobei
X Hauptversion Y Unterversion Z Patchlevel
<status>
Dieser Wert besteht aus einem der folgenden Möglichkeiten:
unstable
Das Paket wurde noch nicht getestet. Eine Installation ist nur Experten zu empfehlen, da dieses Paket noch erhebliche Fehler und Ungereimtheiten enthalten kann. Jedes Paket erhält zu Beginn diesen Status.
testing
Dieses Paket wurde schon getestet und die gröbsten Fehler wurden beseitigt. Es können allerdings noch Fehler auftreten, allerdings läuft es im Standardbetrieb stabil. Ein Package erhält erst diesen Status, wenn mindestens 5 Benutzer dieses Package installiert haben und alle gemeldeten Fehler vom Autor beseitigt wurden.
stable
Dieses Paket ist ausreichend getestet, daß es auch in vielen Kombinationen mit anderen Programmen und Treibern wie erwartet arbeitet. Dokumentation ist vorhanden. Ein Paket erhält erst diesen Status, wenn es vorher den Status ``testing besaß und ein allgemeiner Konsens (in der Developer-Mailingliste o.ä.) darüber besteht.
<section>
Dieser Wert ordnet das Package in eine bestimmte Kategorie ein. Darüber lässt sich eine Menüauswahl o.ä. realisieren. Es existieren folgende Möglichkeiten für diesen Wert:
* admin - admin-tools zum installieren und konfigurieren * utils - sed, grep, links und co - alles was auf der console hilft * devel - gcc und co * game - spieleproxies etc * interpreter - perl, ruby, python und co. * lib - zlib, openssl und co * net - alles rund ums netzwerk * news - alles rund um news * mail - alles rund um mail * misc - alles andere * web - alles rund ums web * database - Datenbanken und Frontends * drivers - Treiber, Kernel-Module
(danke an Oliver Dawid)
<require-package>
Diese Wert definiert eine Abgängigkeit zwischen dem beschriebenen Package und einem anderen Package. Dieses Package wird durch seinen Dateinamen (inklusive relativem Pfad zum aktuellen Package oder absoluter URL) angegeben. Sollte eine bestimmte Mindestversion gefordert werden, so kann diese optional durch ein Leerzeichen getrennt hinter dem Dateinamen angegeben werden.
Ist das beschriebene Package von mehrere Packages abhängig, so kann das <require-package>-Tag mehrfach vorkommen. Gibt es keine Abhängigkeiten, so kann es entfallen.
Die (immer vorhandene) Abhängigkeit zum Package base muss nicht explizit genannt werden, es sein denn, eine bestimmte Version wird vorausgesetzt.
Beispiele:
<require-package>inet.tar.gz.info</require-package> <require-package>../updates/update.tar.gz.info 1.0.5</require-package> <require-package>http://download.eisfair.org/packages/updates/update.tar.gz.info 1.0.5</require-package>
Das Tag gibt an, welche Unterpakete vom Hauptpaket selbständig geladen werden. Diese Angaben dienen lediglich der Information, z.B. für eisfair-Download-Mirror-Systeme.
Syntax:
LOCATION
Die Form von LOCATION entspricht derselben wie für <require-package>.
Update eines Packages
Wenn ein Package upgedatet wird, sind folgende Punkte zu beachten:
* updaten des <version>-tags * eventuell Rückstufung des <status>-Tags
Beispiel
Anbei ein kleines Beispiel, daß obige Definitionen illustrieren soll.
<package> <name>inet</name> <short>Inet services (pure-ftpd \& ssh, inetd, telnet)</short> <version>0.10.4</version> <date>2002/01/02</date> <author>Joerg Hoh, joerg@joerghoh.de</author> <status>stable</status> <section>net</section> <require-package>base tools</require-package> <description> Dieses Package beinhaltet einen Grundstock an Internet-Diensten:
-pureftpd: FTP-Server (pure-ftpd.sourceforge.net, Version 1.0.2) -sshd: SSH-Server, inklusive Generator für eigenen SSH-Keys, SSH-Client (www.openssh.org, Version 3.0.2p1) -inetd: Wird von vielen anderen Diensten benötigt -telnet: Dienst zur Fernadministration; SICHERHEITSRISIKO!! Für weitere Informationen: http://www.joerghoh.de/eisfair/doc/inet.html </description> </package>
Dokumentation
Zu jedem Paket sollte es Dokumentation geben, in der zumindest folgende Punkte genauer erklärt werden:
* Welche weiteren Pakete werden benötigt? * Der Installationsablauf * Eventuelle Konfigurationsdateien und die in ihr definierten Variablen * Die Punkte im Setup-Programm, soweit sie dieses Paket betreffen * Die Funktionen des Pakets * Wie arbeitet dieses Paket mit anderen Pakete zusammen?
Die Texte, die in dieser Dokumentation enthalten sind, wurden mithilfe von LATEXverfasst. Daraus lassen sich sehr einfach andere Formate (wie PDF und das geforderte Textformat für die Dokumentation unter /usr/share/doc) erzeugen.
Wer ebenfalls LATEXbenutzen will, der kann sich von Jörg Hoh (joerg@eisfair.org) das dazu notwendige Style-File besorgen.
Gruppen- und User-IDs
Um weiteres Chaos zu vermeiden, wurde jetzt eine Liste von uids und gids festgelegt, an die sich alle weiteren Packages halten sollte. Die Liste wurde aus den Einträgen von Debian Woody und SuSE gemischt, wobei im Zweifelsfall Debian das letzte Wort hatte.
Username uid gid root 0 0 daemon 1 1 bin 2 2 sys 3 3 lp 4 7 games 5 5 man 6 100 mail 8 8 news 9 9 uucp 10 10 proxy 13 13 at 25 - postgres 26 26 majordom 30 31 postgres 31 32 wwwrun 30 33 backup 34 34 operator 37 37 list 38 38 irc 39 39 ftp 40 49 gnats 41 41 exim 42 42 named 44 44 postfix 51 51 mysql 60 2 zope 64 2 sshd 71 65 firebird 84 84 nobody 65534 65534 identd 100 65534
Gruppenname gid root 0 daemon 1 bin 2 sys 3 adm 4 tty 5 cdisk 6 lp 7 mail 8 news 9 uucp 10 proxy 13 kmem 15 dialout 20 fax 21 voice 22 cdrom 24 floppy 25 tape 26 sudo 27 audio 29 dip 30 majordom 31 postgres 32 www-data 33 backup 34 operator 37 list 38 irc 39 src 40 gnats 41 trusted 42 utmp 43 video 44 ftp 49 staff 50 postfix 51 maildrop 59 games 60 man 62 sshd 65 users 100 maschines 777 nobody 65533 nogroup 65534
Wer meint, daß in dieser Liste ein Eintrag fehlt, der solle sich melden.
Definition regulärer Ausdrücke
Reguläre Ausdrücke sind wie folgt definiert:
Regulärer Ausdruck: Eine oder mehrere Alternativen, getrennt durch '|', z.B. 'ro|rw|no'. Trifft eine der Alternativen zu, trifft der ganze Ausdruck zu (hier wären 'ro', 'rw' und 'no' gültige Ausdrücke).
Eine Alternative ist eine Verkettung mehrerer Teilstücke, die einfach aneinandergereiht werden.
Ein Teilstück ist ein ``Atom, gefolgt von einem einzelnen '*', '+', '?' oder '{min, max}'. Die Bedeutung ist wie folgt:
* 'a*' - beliebig viele a's einschließlich kein a * 'a+' - mindestens ein a, sonst beliebig viele a's * 'a?' - kein oder ein a * 'a{2,5} - zwei bis 5 a's * 'a{5} - 5 a's * 'a{2,} - mindestens 2 a's
Ein ``Atom ist ein
* regulärer Ausdruck eingeschlossen in Klammern, z.B. (a|b)+ trifft auf eine beliebige Zeichenkette zu, die mindestens ein a oder b enthält, sonst aber beliebig viele und in beliebiger Reihenfolge * ein leeres Paar Klammern steht für einen ``leeren Ausdruck * ein Ausdruck mit eckigen Klammern '[]' (siehe weiter unten) * ein Punkt '.', der auf irgend ein einzelnes Zeichen zutrifft, z.B. '.+' trifft auf eine beliebige Zeichenkette zu, die mindestens ein Zeichen enthält * ein '^' steht für den Zeilenanfang, z.B. '^a.*' trifft auf eine Zeichenkette zu, die mit einem a anfängt und in der beliebige Zeichen folgen, 'a' oder 'adkadhashdkash' * ein '$' steht für das Zeilenende * ein ' ' gefolgt von einem der Sonderzeichen '^.[$()|*+?{'` steht für genau das zweite Zeichen ohne seine spezielle Bedeutung * ein normales Zeichen trifft auf genau das Zeichen zu, z.B. 'a' trifft auf genau 'a' zu.
Ein Ausdruck mit rechteckigen Klammern bedeutet folgendes
* '[x-y]' - trifft auf irgend ein Zeichen zu, das zwischen x und y liegt, z.B. '[0-9]' steht für alle Zeichen zwischen 0 und 9; '[a-zA-Z]' für alle Buchstaben, egal ob groß oder klein
* '[^x-y]' - trifft auf irgendein Zeichen zu, das nicht im angegebenen Intervall liegt
* '[:character_class:] - trifft auf ein Zeichen der Zeichen-Klasse zu. Relevante Standardzeichenklassen sind: alnum, alpha, blank, digit, lower, print, punct, space, upper, xdigit.
Beispiele für Reguläre Ausdrücke
Sehen wir uns das mal an einigen Beispielen an:
Numerisch: Ein numerischer Wert besteht aus mindestens einer, aber beliebig vielen Zahlen. Mindestens ein, aber beliebig viele drückt man mit '+' aus, eine Zahl hatten wir schon als Beispiel. Zusammengesetzt ergibt das:
NUMERIC = '[0-9]+' oder alternativ NUMERIC = 'digit:+'
NOBLANK: Ein Wert, der keine Leerzeichen enthält ist ein beliebiges Zeichen (außer dem Leerzeichen) und davon beliebig viele:
NOBLANK = '[^ ]*'
bzw. wenn der Wert zusätzlich auch nicht leer sein soll:
NOBLANK = '[^ ]+'
Disk und Partition: Gültige Bezeichner für eine Disk beginnen mit hd bei IDE-Disks bzw sd bei SCSI-Disks. Dann folgen Buchstaben von a-z (a für die erste Disk, b für die 2., ...) und bei Partitionen die Zahlen 1-8 (1-4 für die ersten 4 Partitionen, die Primär bzw. Extended (nur eine) sein können und 5-8 für die logischen Partitionen innerhalb einer extended Partition). Die Ausdrücke sehen dann wie folgt aus:
DISK = '(hd|sd)[a-z]' PARTITION = '(hd|sd)[a-z][1-8]'
Sehen wir uns das ganze nochmal am Beispiel der IP-Addresse an. Eine IP-Adresse besteht aus 4 Octets, die mit einem '.' getrennt sind. Ein Octet kann eine Zahl zwischen 0 und 255 sein. Definieren wir als erstes ein Octet. Es kann
eine Zahl zwischen 0 und 9 sein: [0-9] eine Zahl zwischen 00 und 99: [0-9][0-9] eine Zahl zwischen 100 und 199: 1[0-9][0-9] eine Zahl zwischen 200 und 249: 2[0-4][0-9] eine Zahl zwischen 250 und 255 sein: 25[0-5]
Da sich die ersten drei Teile stark ähneln, kann man sie zusammenfassen:
* ein Zahl zwischen 0 und 199: 1?[0-9]?[0-9] (die ersten beiden Stellen können, aber müssen nicht da sein)
Das ganze sind Alternativen, also fassen wir sie einfach mittels '|' zu einem Ausdruck zusammen: '1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]' und haben damit ein Octet. Daraus können wir nun eine IP-Adresse machen, 4 Octets mit Punkten voneinander getrennt (der Punkt muß mittels backslash gequotet werden, da er sonst für ein beliebiges Zeichen steht). Basierend auf der Syntax der Exp-Files sieht das ganze dann wie folgt aus:
OCTET = '1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]' IPADDR = '((RE:OCTET)\.){3}(RE:OCTET)'
Erweiterte Prüfungen der Konfiguration
Manchmal ist es notwendig, komplexere Überprüfungen durchzuführen. Beispiele für solche komplexeren Dinge wären z.B. Abhängigkeiten zwischen Paketen oder Bedingungen, die nur erfüllt sein müssen, wenn Variablen bestimmte Werte annehmen. So muß z.B. bei Auswahl eines PCMCIA-ISDN-Adapters auch das PCMCIA-Paket installiert werden.
Um diese Überprüfungen durchführen zu können, kann man in /etc/check.d/<PACKAGE>.ext kleinere Tests schreiben. Die Sprache besteht aus folgenden Elementen:
1. Schlüsselwörter:
* Kontrollfluß:
o if (expr) then statement else statement fi o foreach var in set_var do statement done o foreach var in var_n do statement done
* Abhängigkeiten: o provides package version x.y.z o depends on package version x.y
* Aktionen: o warning ``warning o error ``error o fatal_error ``fatal error o set var = value o stat (filename, res) o split (string, set_variable, character) 2. Datentypen: strings, numerische Werte, Versionsnummern, Arrays 3. Logische Operationen: <, ==, >, !=, !, &&, ||, =, copy_pending
Kommunikation mit dem Nutzer
Mit Hilfe von Funktionen kann man Nutzer warnen, einen Fehler signalisieren oder die Prüfung sofort abbrechen. Das Format sieht wie folgt aus:
* warning ``text * error ``text * fatal_error ``text
Im Text kann man auf Variablen Bezug nehmen, indem man einfach den Namen mit einem vorangestellten '$' oder '%' Zeichen in den Text schreibt (evtl. in eingeschlossen, um den Variablenamen vomm umgebenden Text abzugrenzen). mkfli4l versucht den darauffolgenden Text (Ziffern, Zahlen, '_') als Variablennamen zu interpretieren und setzt bei einem vorangestellten '$' den Inhalt der Variablen an dieser Stelle ein, wenn Sie definiert ist, bzw bei einem vorangestellten '%' den vollständigen Namen der aktuellen %-Variable. Sonst steht der originale Text da. Will man wirklich ein '$' oder ein '%' im Text haben, schreibt man '$$' bzw. '%%'.
Zuweisungen
Benötigt man aus irgend einem Grund eine temporäre Variable, kann man diese einfach mit ``set var [= value] anlegen. Die Variable darf kein Config-Variable sein. Läßt man den ``= value Teil weg, wird die Variable einfach auf ``yes gesetzt, so daß man sie hinterher einfach in einer if-Anweisung testen kann. Wird ein Zuweisungsteil angegeben, kann hinter dem Gleichheitszeichen alles stehen, normale Variablen, Indizierte Variablen, Zahlen, Zeichenketten, Versionen.
Arrays
Will man auf einzelne Elemente einer %-Variablen (eines Arrays) zugreifen, kann man das wie gewohnt mit %_var[index] tun, wobei für jedes % Zeichen ein [ Index ] auftauchen muß.
Abfragen von Eigenschaften einer Datei - stat
stat() ermöglicht es, Eigenschaften einer Datei abzufragen. Zur Verfügung gestellt wird im Augenblick lediglich die Größe einer Datei, andere Attribute sind aber leicht hinzuzufügen. Abfragen sehen wie folgt aus (wobei die verwendeten Parameter nur Beispiele sind):
stat (``unix/Makefile, test)
Danach sind zwei Variablen definiert:
* test_res: Resultat des Systemrufs stat() (``OK, wenn Systemruf erfolgreich, sonst Fehlermeldung des Systemrufs) * test_size: Größe der Datei
Das könnte dann z-B. so aussehen:
stat (``unix/Makefile, test) if (``$test_res == ``OK) then warning ``test_size = $test_size else error ``Error '$test_res' while trying to get size of ... fi
Auseinandernehmen von Parametern - split
Oftmals werden Variablen mir mehreren Parametern belegt, die dann in Startup-Scripten erst wieder auseinandergenommen werden. Will man diese bereits vorher auseinandernehmen und Tests mit ihnen durchführen, nimmt man split.
split (string, %_var, character)
Der String kann durch eine Variable, %-Variable oder direkt als String angegeben werden. mkfli4l zerlegt ihn an den Stellen, an denen das Trennzeichen auftaucht und erzeugt je eine Instanz der %-Variablen. Über diese kann man dann hinterher Tests laufen lassen. Steht zwischen zwei Trennzeichen nichts, wird eine Instanz mit einer leeren Zeichenkette als Wert erzeugt. Ausnahme ist ' ', hier werden alle whitespaces konsumiert und keine leeren Variablen erzeugt.
Sollen die bei der Zerlegung entstandenen Elemente in einem numerischen Kontext verwendet werden (z.B. als Index), muß das beim Aufruf von Split spezifiert werden. Das geschieht durch das zusätzliche Attribut 'numeric'. Der Aufruf sieht dann wie folgt aus:
split (string, %_var, character, numeric)
Kontrollfluss
if (expr) then statement else statement fi
Eine klassische if-Konstruktion, wie man sie kennt. Ist die Bedingung war, wird der then-Teil ausgeführt, ist die Bedingung falsch, wird der else-Teil ausgeführt.
Will man Tests über %-Variablen durchführen, muß man jede einzelne Variable testen. Dazu gibt es das foreach-Statement in zwei Varianten:
foreach loop_var in set_var do statement done
Diese Schleife iteriert über alle %-Variablen, angefangen bei eins bis zum in der dazugehörigen (in /etc/check.d/<PACKAGE>.txt stehenden) Variable_n stehenden Index n. Die Laufvariable loop_var nimmt dabei die jeweiligen Werte der %-Variablen an.
Das Statement kann dabei eine der oben beschriebenen Funktionen if, foreach, provides, depends, warning, error oder fatal_error sein.
Will man genau eine %-Variable testen, kann man diese mittels var_%[index] auswählen. Der index kann dabei eine normale Variable, ein String, oder wiederum ein indiziertes Array sein.
foreach loop_var in var_n do statement done
Diese Schleife läuft von 1 bis var_n. Man kann die Schleifenvariable loop_var dazu benutzen, um _% Variablen zu indizieren. Will man also nicht nur über eine _% Variable iterieren, sondern über mehrere gleichzeitig, nimmt man diese Variante der Schleife und verwendet die loop_var zum Indizieren mehrerer _% Variablen.
Expressions
Die Expressions erlaubt so gut wie alles, was man von einer Programmiersprache gewöhnt ist. Ein in einem Ausdruck auftauchender Wert 'val' kann eine Variable, ein String oder ein indiziertes Array sein. Variablen in Strings werden dabei wie oben beschrieben ersetzt. Ein Test auf die Gleichheit zweier Variablen könnte also so aussehen:
var1 == var2 ``$var1 == ``$var
Zu beachten ist dabei, daß der Vergleich in Abhängigkeit vom Typ der Variable erfolgt, der in /etc/check.d/<PACKAGE>e festgelegt wurde. Variablen, die als Typnamen einen mit NUM beginnenden Namen haben erhalten einen numerischen Typ. Ist einer der beiden Variablen numerisch, erfolgt der Vergleich auf numerischer Basis, d.h. die Zeichenketten werden in Zahlen umgewandelt und dann vergleichen. Sonst erfolgt der Vergleich auf String-Basis; ein Vergleich von '05' und '5' geht ergibt ungleich, ein Vergleich von '18' und '9' ergibt '18' < '9'.
Für den Vergleich von Versionen wird das Hilfkonstrukt numeric(version) eingeführt, welches den numerischen Wert für einen Versionsstring für Vergleichszwecke bestimmt . numeric(version) == sub_version + 1000 * minor_version + 10000 * major_version:
Eine Vollständige Auflistung aller Ausdrücke ist in Tabelle 35.1 zu finden.
Tabelle 35.1: Logische Ausdrücke
expr true if
id id == 'yes'
val == val strings/numerische Werte sind identisch
val != val strings/numerische Werte sind verschieden
val == number numerischer Wert von val == number
val != number numerischer Wert von val != number
val < number numerischer Wert von val < number
val > number numerischer Wert von val > number
val == version numeric(val) == numeric(version)
val < version numeric(val) < numeric(version)
val > version numeric(val) > numeric(version)
( expr ) Ausdruck in Klammern ist wahr
expr && expr beide Ausdrücke sind wahr
expr || expr mind. einer der beiden Audrücke ist wahr
copy_pending(id) siehe Beschreibung
Prüfen, ob in Abhängigkeit vom Wert einer Variable ein File kopiert wurde: copy_pending
Mit den im Check-Prozeß gewonnenen Informationen prüft die Funktion copy_pending() ob in Abhängigkeit vom Wert einer Variable ein File kopiert wurde, oder nicht. Das kann man verwenden, um z.B. zu testen, ob der vom Nutzer angegebene Treiber auch wirklich existiert und kopiert wurde. copy_pending akzeptiert den zu prüfenden Namen in Form einer Variablen oder eines Strings. Im String werden Ersetzungen wie oben beschrieben durchgeführt, so daß man z.B. mittels einer foreach Schleife und einem ``%loop_var alle Inkarantionen einer %-Variable prüfen kann.
copy_pending() prüft dazu, ob
* die Variable aktiv ist (wenn sie von einem opt abhängt, muß dieses auf 'yes' gesetzt sein)
* die Variable in einem opt/package.txt File referenziert wurde
* ob in Abhängigkeit vom aktuellen Wert ein File kopiert wurde.
Ein kleines Beispiel für die Anwendung all dieser Funktionen findet man im template package.
Systemdateien aktualisieren
Manchmal ist es notwendig Einträge zu Systemdateien hinzuzufügen bzw. diese zu ändern. Damit die Dateien nicht direkt bearbeitet werden müssen, wurde ab dem base-Paket v1.0.8 eine einheitliche Schnittstellenfunktion realisiert. Initial wurden Funktionen für das Aktualisieren von /etc/host.allow, /etc/host.deny, /etc/services und /etc/inittab implementiert.
/etc/host.allow
Will ein Programm Einträge zu der Datei /etc/hosts.allow hinzufügen, so muß es eine Datei /etc/hosts.allow.<package-name> schreiben, die wie folgt aussehen sollte:
- /etc/hosts.allow.nfsserver list file generated by /var/install/config.d/nfsserver.sh v1.0.1-3
portmap: 192.168.6.0/24 lockd: 192.168.6.0/24 rquotad: 192.168.6.0/24 mountd: 192.168.6.0/24 statd: 192.168.6.0/24
Um die Änderungen bzw. Ergänzungen abschließend zu übernehmen muß noch das Programm '/var/install/bin/update-hosts.allow <package-name>' aufgerufen werden. Bei der Deinstallation des Paketes muß nur die Datei /etc/hosts.allow.<package-name> gelöscht und erneut das update-hosts.allow- Script aufgerufen werden.
/etc/host.deny
Will ein Programm Einträge zur Datei /etc/hosts.deny hinzufügen, so muß es eine Datei /etc/hosts.deny.<package-name> schreiben, die wie folgt aussehen sollte:
- /etc/hosts.deny.nfsserver list file generated by /var/install/config.d/nfsserver.sh v1.0.4-1
portmap: ALL lockd: ALL mountd: ALL rquotad: ALL statd: ALL
Um die Änderungen bzw. Ergänzungen abschließend zu übernehmen muß noch das Programm '/var/install/bin/update-hosts.deny <package-name>' aufgerufen werden. Bei der Deinstallation des Paketes muß nur die Datei /etc/hosts.deny.<package-name> gelöscht und erneut das update-hosts.deny- Script aufgerufen werden.
/etc/services
Will ein Programm Einträge zur Datei /etc/services hinzufügen, so muß es eine Datei /etc/services.<package-name> schreiben, die wie folgt aussehen sollte:
- /etc/services.antispam list file generated by /var/install/config.d/antispam.sh v1.2.2
spamd 783/tcp # SpamAssassin daemon
Um die Änderungen bzw. Ergänzungen abschließend zu übernehmen muß noch das Programm '/var/install/bin/update-services <package-name>' aufgerufen werden. Als Basis wird immer die Datei /etc/services.std verwendet deren Einträge dann ersetzt bzw. zu der neue Einträge hinzugefügt werden. Bei der Deinstallation des Paketes muß nur die Datei /etc/services.<package-name> gelöscht und erneut das update-services-Script aufgerufen werden.
/etc/inittab
Will ein Programm Einträge zur Datei /etc/inittab hinzufügen, so muß es eine Datei /etc/inittab.<package-name> schreiben, die wie folgt aussehen sollte:
- /etc/inittab.vbox list file generated by /var/install/config.d/vbox.sh v1.0.4-1
I6:2345:respawn:/usr/local/vbox/sbin/vboxgetty -d /dev/ttyI6 I7:2345:respawn:/usr/local/vbox/sbin/vboxgetty -d /dev/ttyI7
Um die Änderungen bzw. Ergänzungen abschließend zu übernehmen muß noch das Programm '/var/install/bin/update-inittab <package-name>' aufgerufen werden. Als Basis wird immer die Datei /etc/inittab.std verwendet deren Einträge dann ersetzt bzw. zu der neue Einträge hinzugefügt werden. Bei der Deinstallation des Paketes muß nur die Datei /etc/inittab.<package-name> gelöscht und erneut das update-inittab-Script aufgerufen werden.
Debug-Modus
Wird die Option -debug an die genannten Scripte übergeben, so werden detailliertere Informationen über eventuell gefundene Fehler ausgegeben.
Beispiel
Die Implementierung wird am Beispiel der Konfiguration des nfsserver-Paketes gezeigt:
...
pgmname=`basename $0`
- set file names
configfile=$testroot/etc/config.d/nfsserver generate_hostsallow=/etc/hosts.allow.nfsserver
- other parameters
nfsserver_version="v1.0.1-3"
...
echo "#" echo "# $generate_hostsallow list file generated by $pgmname $nfsserver_version" echo "#"
...
- set access rights
chown root $generate_hostsallow chgrp root $generate_hostsallow chmod 0640 $generate_hostsallow
- update file
/var/install/bin/update-hosts.allow $pgmname
...
ip-up/down Mechanismus
Sollen gewisse Aktionen nach dem Start bzw Stop einer Internetverbindung durchgeführt werden, dann kann man in das Verzeichniss /etc/ppp/ Skripte ablegen, die diese Aktionen durchführen. Der Name des Skripts bestimmt, wann es aufgerufen wird. Es gelten daher folgende Namenskonventionen (alle Namensteile sind durch einen Punkt (.) voneinander getrennt.
* Der Anfang wird durch die Namen ,,ip-up`` oder ,,ip-down`` gebildet. Ein Skript, dessen Name mit mit ,,ip-up`` beginnt, wird beim Starten der Internetverbindung ausgeführt, eines mit ,,ip-down`` im Namen nach Beendigung einer Internetverbindung. * Der nächste Namensteil ist eine dreistellige Zahl. Diese definieren die Reihenfolge, in der die Skripte abgearbeitet werden. Die Zahlen von 000 bis 100 sind für das Routing- und Basis-Paket selbst reserviert, alle anderen Pakete dürfen die Zahlen von 101 bis 999 benutzen. * der letzte Namensteil ist frei wählbar und sollte im Normalfall Aufschluss darüber geben, was dieses Skript macht bzw zu welchem Paket es gehört.
Als Beispiel sei
ip-up.010.dns
genannt, welche als Bestandteil des Routing-Pakets nach dem Start der Internetverbindung die DNS-Server im System bekannt macht.
ACHTUNG In den ,,ip-down,, Skripten dürfen keine Aktionen durchgeführt werden, die eine erneute Internet-Einwahl zur Folge hat.
ACHTUNG Diese Skripts dürfen nicht mit exit 0 abgeschlossen werden.
Innerhalb der Skripte können folgende Variablen benutzt werden:
$real_interface
- das aktuelle Interface
$interface
- das imond-Interface
$tty
- verbundenes Terminal, möglicherweise leer
$speed
- die Verbindungsgeschwindigkeit
$local
- die eigene IP-Adresse
$remote
- die IP-Adresse der Gegenstelle
Hinweise und Tricks
Um Probleme mit den Benutzerrechten (zum Beispiel Dateien, die einem User mit der ID 501 gehören, der auf dem eisfair-Server gar nicht existiert) zu verhindern, empfiehlt es sich, Packages mit
tar -czv --owner=root --group=root -f package.tar.gz *
zu verpacken. Damit gehören die entpackten Dateien erstmals dem Superuser; dieser Zustand kann, sofern er gewünscht ist, in dem Installationsskript tmpinstall.sh geändert werden.