Paketbau/SUSE-Paketkonventionen/Init-Skripte

aus openSUSE, der freien Wissensdatenbank




Inhaltsverzeichnis

7. Init-Skripte

In diesem Kapitel wird beschrieben, wie Init-Skripte unter openSUSE benannt, erstellt und installiert werden. Sie müssen LSB-konform sein, wie es unter http://refspecs.freestandards.org/LSB_2.0.1/LSB-generic/LSB-generic/sysinit.html beschrieben wird.


7.1. Name

Init-Skriptnamen müssen LSB-konform sein; sie müssen also unter http://www.lanana.org/lsbreg/init/init.txt eingetragen sein. Sie können einen neuen Namen wie unter http://www.lanana.org/lsbreg/instructions.html beschrieben registrieren.


7.2. Struktur

Die Struktur eines Init-Skripts ist in /etc/init.d/skeleton gut beschrieben. Sie können diese Datei auch als effiziente Vorlage für neue Init-Skripte nutzen.

Init-Skripte sind Shell-Skripte, weshalb der Inhalt mit den gewöhnlichen Kopfdaten beginnt:

#!/bin/sh

oder

#!/bin/bash

Danach folgt in der Regel ein Kommentarabschnitt, in welchem Sie Informationen über den Autor, Vervielfältigungsrechte oder Lizenzen unterbringen sollten. Die Datei muss darüber hinaus spezielle Kommentarkopfdaten enthalten, die einige Metainformationen über das Init-Skript bereitstellen. Der Abschnitt 7.3, “Kommentarkonvetionen” enthält weitere Details dazu. Im Abschnitt 7.4, “Standard-Facilities” finden Sie eine Liste der unter openSUSE verfügbaren Standard-Facilities.

Dieses Beispiel entstammt /etc/init.d/esound:

# Copyright (c) 1995-2002 SUSE Linux AG, Nuernberg, Germany.
 # All rights reserved.
 #
 # Author: Stanislav Brabec, feedback to http://www.suse.de/feedback
 #
 ### BEGIN INIT INFO
 # Provides:          esound
 # Required-Start:    alsasound
 # Should-Start:      $network portmap
 # Required-Stop:     alsasound
 # Should-Stop:      $network portmap
 # Default-Start:     5
 # Default-Stop:
 # Short-Description: Sound daemon with network support
 # Description:       Starts esound server to allow remote access to sound
 #       card. To use esound locally, you do not need to start this
 #       server on boot. You should edit server settings before
 #       starting it via sysconfig editor: Network/Sound/Esound
 ### END INIT INFO

Danach folgen in der Regel Prüfungen, ob der Dienst korrekt installiert ist und die zugehörigen Konfigurationsdateien werden eingelesen. Im Fall eines Problems müssen die LSB-konformen Fehlerwerte ausgegeben werden. Weitere Details dazu finden Sie in Abschnitt 7.4, “Exit-Statuscodes”.

Dieses Beispiel entstammt /etc/init.d/ypbind:

YPBIND_BIN=/usr/sbin/ypbind
 test -x $YPBIND_BIN || { echo "$YPBIND_BIN not installed";
         if [ "$1" = "stop" ]; then exit 0; else exit 5; fi; }
 
 YPBIND_CONFIG=/etc/sysconfig/ypbind
 test -r $YPBIND_CONFIG || { echo "$YPBIND_CONFIG not existing";
         if [ "$1" = "stop" ]; then exit 0; else exit 6; fi; }
 
 # Read config
 . $YPBIND_CONFIG

Dann werden für gewöhnlich die rc-Statusfunktionen bezogen und der rc-Status wird zurückgesetzt. Dieses Beispiel entstammt /etc/init.d/network:

. /etc/rc.status
rc_reset

Danach werden die benötigten Aktionen implementiert. In der Datei /etc/init/d/skeleton finden Sie dazu Beispielcode und wertvolle Kommentare. Das folgende Beispiel entstammt /etc/init.d/cron:

case "$1" in
    start)
        echo -n "Starting CRON daemon"
        startproc $CRON_BIN
        rc_status -v
        ;;
    stop)
        echo -n "Shutting down CRON daemon"
        killproc -TERM $CRON_BIN
        rc_status -v
        ;;
    try-restart)
        $0 status >/dev/null &&  $0 restart
        rc_status
        ;;
    restart)
        $0 stop
        $0 start
        rc_status
        ;;
    force-reload)
        echo -n "Reload service Cron"
        checkproc $CRON_BIN
        rc_status -v
        ;;
    reload)
        rc_status -v
        ;;
    status)
        echo -n "Checking for Cron: "
        checkproc $CRON_BIN
        rc_status -v
        ;;
    probe)
        ;;
    *)
        echo "Usage: $0 {start|stop|status|try-restart|\
restart|force-reload|reload|probe}"
        exit 1
        ;;
esac

Zum Schluss muss dass Init-Skript mit dem korrekten Exit-Status enden. Aus diesem Grund ist die Funktion rc_exit in aller Regel der letzte Befehl.


7.3. Kommentarkonventionen

Init-Skripte sind Shell-Skripte, weshalb die Kommentare durch '#' abgegrenzt werden und ohne jede Beschränkung genutzt werden können. Das war nun etwas zuviel versprochen, denn es gibt doch eine Einschränkung; LSB definiert einen speziellen Kommentarkopfbereich, um einige Metainformationen über das Init-Skript bereitzustellen. Diese Kopfdaten müssen in jedem Init-Skript enthalten sein und sind folgendermaßen aufgebaut:

### BEGIN INIT INFO
 # Provides:                   boot_facility_1 [ boot_facility_2 ...]
 # Required-Start:             boot_facility_1 [ boot_facility_2 ...]
 # Should-Start:               boot_facility_1 [ boot_facility_2 ...]
 # Required-Stop:              boot_facility_1 [ boot_facility_2 ...]
 # Should-Stop:                boot_facility_1 [ boot_facility_2 ...]
 # Default-Start:              run_level_1 [ run_level_2 ...]
 # Default-Stop:               run_level_1 [ run_level_2 ...]
 # Short-Description:          single_line_description
 # Description:                multiline_description
 ### END INIT INFO

Diese Schlüsselwörter haben die folgende Bedeutung:

  • Provides definiert Namen von Facilities, die von diesem Skript gestartet werden. In der Regel ist es der Name des Daemons. Falls mehr als ein Paket die selbe Facility bereitstellen kann (bspw. sendmail vs. postfix, dhcpcd vs. dhclient), sollten die Init-Skripte von beiden die selben Facility-Namen verwenden.
  • Required-Start gibt an, welche Facilities zum Starten und Ausführen dieses Dienstes verfügbar sein müssen. Das Init-Skriptsystem sollte sicher stellen, dass die benötigten Facilities gestartet werden, bevor das anfragende Skript gestartet wird.
  • Should-Start ist ein optionales Feld. Die Funktion ist ähnlich der von Required-Start, definiert aber keine harten Abhängigkeiten. Falls ein unter Should-Start nicht installiert oder zum Starten aktiviert ist, wird dies stillschweigend ignoriert.
  • Required-Stop gibt an, welche Facilities während des Abschalten des Dienstes immer noch aktiviert sein müssen. Das Init-Skriptsystem sollte ein Stoppen der hier aufgeführten Dienste vermeiden, bis das anfragende Skript gestoppt ist.
    Dieses Kopfdatum wird unter SUSE Linux/openSUSE zur zeit ignoriert, da dass SUSE-Boot-Skript-Konzept ein anderes Verknüpfungsschema nutzt (Weitere Informationen dazu finden Sie in der man page init.d(7)).
  • Should-Stop ist ein optionales Feld. Die Funktion ist ähnlich der von Required-Stop, defniert aber keine harten Abhängigkeiten. Falls ein unter Should-Stop nicht installiert oder zum Starten aktiviert ist, wird dies stillschweigend ignoriert.
  • Default-Start gibt an, in welchen runlevels der Dienst standardmäßig gestartet werden soll. Die runlevels wurden an SUSE Linux 7.1 geändert.
  • Default-Stop gibt an, in welchen runlevels das Skript standardmäßig gestoppt werden soll.
    Dieses Kopfdatum wird unter SUSE Linux/openSUSE zur zeit ignoriert, da dass SUSE-Boot-Skript-Konzept ein anderes Verknüpfungsschema nutzt (Weitere Informationen dazu finden Sie in der man page init.d(7)).
  • Short-Description enthält eine einzeilige Beschreibung der Funktion dieser Facility. Sie wird beispielsweise im YaST Runlevel-Editor angezeigt.
  • Description enthält eine mehrzeilige Fuktionsbeschreibung dieser Facility. Jede neue Zeile muss dabei mit einem '#' gefolgt von einem Tabulator oder mindestens zwei Leerzeichen beginnen. Die mehrzeilige Beschreibung wird von der ersten Zeile beendet, die diese Kriterien nicht erfüllt. Diese Informationen werden ebenfalls im YaST Runlevel-Editor angezeigt.


Die LSB erlaubt die Definition von distributionsspezifischen Erweiterungen für die Kopfdaten. Solche Schlüsselwörter wird ein X-VendorTag- vorangestellt. Die folgenden Schlüsselwörter sind unter SUSE Linux/openSUSE verfügbar:

  • X-SuSE-Should-Start hat die gleiche Bedeutung wie Should-Start. Seitdem die LSB 2.0 Should-Start enthält ist es überflüssig.
  • X-SuSE-Should-Stop hat die gleiche Bedeutung wie Should-Stop. Seitdem Should-Stop Teil der LSB 2.0 wurde ist es überflüssig.
  • X-UnitedLinux-Default-Enabled gibt an, ob der Dienst standardmäßig aktiviert werden soll. Die möglichen Werte sind yes oder no. Primär wurde dies für United Linux eingeführt, kann aber auch unter SUSE Linux/openSUSE Produkten genutzt werden.
  • X-UnitedLinux-Should-Start ist das gleiche wie X-SuSE-Should-Start nur für United Linux.
  • X-UnitedLinux-Should-Stop ist das gleiche wie X-SuSE-Should-Stop nur für United Linux.


7.4. Standard-Facilities

Wie von der LSB gefordert bieten die SUSE Linux/openSUSE-Facilities einige Standard-Facility-Namen an, die in /etc/insserv.conf definiert sind. Zur Zeit werden die Folgenden Fycility-Namen bereitgestellt:

  • $local_fs — Alle lokalen Dateisysteme werden eingebunden. Die meisten Dienste sollten dies benötigen.
  • $remote_fs — Alle entfernten Dateisysteme werden eingebunden. Da /usr ausgelagert sein kann, sollten viele Dienste auch dies benötigen.
  • $syslog — Die Systemprotokollierungs-Facility ist aktiviert.
  • $network — Grundlegende Netzwerkfunktionen (Netzwerkkarten usw.) sind aktiviert.
  • $named — Hostname-Auflösung ist verfügbar.
  • $netdaemons — Alle Netzwerk-Daemons laufen. Dies wurde in LSB 1.2 entfernt, wird aber bis heute aus Kompatibilitätsgründen beibehalten.
  • $time — Die Systemzeit wurde korrekt gesetzt.
  • $portmap — SunRPC-Portmapping-Dienst ist verfügbar.


7.5. Aktionen

Gemäß der LSB-Definitionen müssen alle Init-Skripte mit den folgenden Argumenten umgehen können:

  • start — Startet den Dienst.
  • stop — Stoppt den Dienst.
  • restart — Stoppt und startet den Dienst neu, wenn dieser bereits läuft. Andernfalls wird der Dienst gleich gestartet.
  • reload — Veranlasst, dass die Konfiguration des Dienstes neu geladen wird, ohne das der Dienst dabei angehalten und neu gestartet wird.
  • force-reload — Veranlasst, dass die Konfiguration neu geladen wird, wenn der Dienst dies unterstützt. Andernfalls wird der Dienst neu gestartet.
  • status — Gibt den aktuellen Status des Dienstes aus.


Die Aktionen The start, stop, restart, force-reload und status müssen von allen Init-Skripten unterstützt werden. Die Aktion reload ist optional.

SUSE definiert darüber hinaus die folgenden, zusätzlichen Aktionen:

  • try-restart — Startet den Dienst nur neu, wenn er vorher aktiv war. Diese Aktion ist mittlerweile Teil der LSB (seit 1.9). Red Hat hat eine ähnliche Aktion namens condrestart.
  • probe — Prüft die Notwendigkeit eines Neustarts. Abhängig vom Dienst wird bei einem notwendigen Neutstart "reload" oder "restart" ausgegeben, andernfalls wird nichts ausgegeben. Diese Aktion ist optional und nicht Teil der LSB (Stand: 1.9).


7.6. Exit-Statuscodes

LSB definiert für Init-Skripte die folgenden Exit-Statuscodes:

Exist-Statuscode Description
0 Erfolg
1 allgemeiner oder unspezifizierter Fehler
2 ungültige oder überschüssige Argumente
3 nicht implementierte Fähigkeiten (bspw. "reload")
4 Nutzer hat unzureichende Rechte
5 Programm ist nicht installiert
6 Programm ist nicht konfiguriert
7 Programm ist nicht am Laufen
8-99 reserviert für zukünftige LSB-Nutzungen
100-149 reserviert für Distributionsnutzung
150-199 reserviert für Anwendungsnutzung
200-254 reserviert

Das Starten eines bereits laufenden Dienstes, das Stoppen oder Neustarten eines nicht laufenden Dienstes und ein Neustart mit force-reload (falls Signalisierung nicht unterstützt wird) werden als Erfolg angesehen.


7.7. Statusfunktionen

Die in /etc/rc.status definierten Funktionen helfen dabei, die aktuellen rc-Statusinformationen in Init-Skripten aufzunehmen, anzuzeigen und zurückzuliefern. Sie können folgendermaßen in ein Init-Skript eingebunden werden:

. /etc/rc.status

Die folgenden Funktionen sind verfügbar:

  • rc_active
    Diese Funktion prüft, ob ein Dienst (durch symbolische Verknüpfungen) aktiviert ist. Sie liefert “0” zurück falls der Dienst in einem Runlevel aktiviert ist und andernfalls “1”.
  • rc_exit
    Diese Funktion beendet ein Init-Skript mit dem Exit-Status des allgemeinen rc-Status.
  • rc_failed [num]
    Diese Funktion setzt den lokalen und den allgemeinen rc-Status auf einen ausgewählten Wert, der durch den Parameter num definiert wird. Standardmäßig wird der Wert “1” genutzt.
  • rc_check
    Diese Funktion prüft den Exit-Status des letzten Kommandos ($?) und setzt den lokalen rc-Status auf diesen Wert, falls der Wert ein anderer als “0” ist. Danach setzt es den allgemeinen rc-Status auf den Wert des lokalen rc-Status, falls sich dieser von “0” unterscheidet. Diese Funktion wird intern von anderen rc-Statusfunktionen genutzt.
  • rc_reset
    Diese Funktion setzt denn allgemeinen und den lokalen rc-Status auf “0”.
  • rc_status [-r] [-s] [-u] [-v[num]
    Diese Funktion prüft, setzt und zeigt den rc-Status an. Standardmäßig geschieht dies still: es wird nur rc_check aufgerufen. Deshalb muss es mit einer Option aufgerufen werden, um den Status anzuzeigen. Die Optionen haben die folgende Bedeutung:
    • -r ruft rc_reset auf. Diese Option lässt sich zusammen mit -v nutzen. Das Kommando rc_status -v -r prüft, setzt und zeigt den aktuellen rc-Status an. Danach wird rc_reset aufgerufen.
    • -s zeigt “skipped” an und setzt den Status auf “3”. Es bezeichnet damit eine nicht implementierte Fähigkeit.
    • -u zeigt “unused” an un setzt den Status auf “3”. Es bezeichnet damit eine nicht implementierte Fähigkeit.
    • -v[num] zeigt den aktuellen Status an und setzt den lokalen Status auf “0”. Standardmäßig wird der Status auf der aktuellen Zeile ausgegeben. Der Parameter num gibt an, dass die Anzeige num Zeilen über der aktuellen Cursor-Position stattfinden soll.


7.8. Installation

Das Init-Skript ist normalerweise Teil des Quellcodepakets und eine eigene Source-Datei. Es wird im Abschnitt %install installiert und im %files-Abschnitt als %config markiert.

Es kann auch eine symbolische Verknüpfung namens rcname angelegt werden, die auf /etc/init.d/name verweist. Die symbolische Verknüpfung wird entweder in /sbin oder in /usr/sbin abgelegt, abhängig vom Präfix, unter dem der Dienst installiert ist. Dies ist sinnvoll bei Init-Skripten, die von Hand gestartet, gestoppt und neu gestartet werden können.

Schlussendlich kann das Init-Skript aktiviert werden, nachdem das Paket installiert wurde, und muss deaktiviert werden, nachdem das Paket entfernt wurde. Der Dienst sollte nach einer Aktualisierung neu gestartet werden und gestoppt werden, bevor das Paket entfernt wird. Die Makros %fillup_and_insserv, %insserv_force_if_yast, %restart_on_update, %insserv_cleanup und %stop_on_removal sind für diese Zwecke gedacht.

Beachten Sie, dass SUSE Linux/openSUSE das Werkzeug insserv bereitstellt, um Init-Skripte zu aktivieren und zu deaktivieren. In der Handbuchseite (man page) von insserv(8) erhalten Sie weitere, detailliertere Informationen. Dieses Werkzeug wird auch von den Makros %fillup_and_insserv, %insserv_force_if_yast und %insserv_cleanup genutzt.

Die Init-Skripte sind unter SUSE Linux/openSUSE standardmäßig deaktiviert, ausgenommen davon sind die, die für die grundsätzliche Systemfunktionalität notwendig sind. Deshalb werden die Makros %fillup_and_insserv und %insserv_force_if_yast nur in Paketen genutzt, die Basisdienste bereitstellen. Nichtsdestotrotz werden Sie auch von Paketen genutzt, die vor SUSE Linux 8.0 Init-Skripte bereitstellten. Dabei wurde ein anderer Ansatz genutzt, um Dienste zu aktivieren und insserv muss ausgeführt werden um die Einstellungen zu aktualisieren. Weitere Details dazu erhalten Sie in den Hinweisen am Ende dieses Kapitels.

Dieses Beispiel entstammt dem Paket ypserv:

Source1:      ypserv.init
Source2:      yppasswdd.init
Source3:      ypxfrd.init
[...]
%install
[...]
mkdir -p $RPM_BUILD_ROOT/etc/init.d
install -m 755 %SOURCE1 $RPM_BUILD_ROOT/etc/init.d/ypserv
install -m 755 %SOURCE2 $RPM_BUILD_ROOT/etc/init.d/yppasswdd
install -m 755 %SOURCE3 $RPM_BUILD_ROOT/etc/init.d/ypxfrd
[...]
ln -sf ../../etc/init.d/yppasswdd       $RPM_BUILD_ROOT/usr/sbin/rcyppasswdd
ln -sf ../../etc/init.d/ypxfrd          $RPM_BUILD_ROOT/usr/sbin/rcypxfrd
ln -sf ../../etc/init.d/ypserv          $RPM_BUILD_ROOT/usr/sbin/rcypserv
[...]
%post
%{fillup_and_insserv ypserv ypxfrd yppasswdd}

%preun
%stop_on_removal ypserv ypxfrd yppasswdd

%postun
%restart_on_update ypserv ypxfrd yppasswdd
%insserv_cleanup

%files
%defattr(-,root,root)
[...]
%config /etc/init.d/yppasswdd
%config /etc/init.d/ypserv
%config /etc/init.d/ypxfrd
[...]
/usr/sbin/rcyppasswdd
/usr/sbin/rcypserv
/usr/sbin/rcypxfrd

Die Namen von Init-Skripten müssen als Parameter bei den zugehörigen Makros angegeben werden, falls Sie aktiviert, neu gestartet oder gestoppt werden sollen. Einzige Ausnahme stellt das Makro %insserv_cleanup dar, welches keine Parameter benötigt, da es sowieso alle symbolischen übrig gebliebenen symbolischen Verknüpfung entfernt.


Hinweis

Vor SUSE Linux 8.0 wurde ein anderes Konzept verwendet, um Dienste in bestimmten Runlevels zu aktivieren. Sie wurden nicht mit insserv sondern durch in /etc/rc_config (/etc/rc_config war ein Vorgänger von /etc/sysconfig) stehende START-Variablen aktiviert. Die Variablen hießen START_XXX, wobei XXX in der Regel der Name des Init-Skripts in Großbuchstaben war. Sie wurden entweder auf “yes” oder “no” gesetzt, wobei “yes” bedeutete, dass der Service aktiviert wurde.

Technisch gesehen rief jedes Paket, dass über ein Init-Skript verfügte, in seinem %post-Skript insserv auf. Dadurch waren alle Dienste “aktiviert” und die Init-Skripte wurden in den vorgesehenen Runlevels immer gestartet. Nach dem Start bezogen die Init-Skripte dann /etc/rc_config mit ein und stoppten die Weiterverarbeitung, wenn die zugehörige START-Variable auf “no” gesetzt war.

Vor SUSE Linux 8.0 wurde in der %preun-Sektion das Kommando sbin/insserv etc/init.d aufgerufen. Dies macht keinen Sinn, denn insserv macht nichts, weil zu diesem Zeitpunkt noch alle Dateien des Pakets vorhanden sind. %insserv_cleanup muss im Abschnitt %postun aufgerufen werden.




Weiter