PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Daemon automaisch starten (Debian)



musketaquid
12.12.06, 23:54
Automatisches starten eines Daemons mit Debian

Einleitung

Dieses Howto soll zeigen, wie ein selbst geschriebenes Script, das als Daemon fungieren soll, sich in das System einbinden lässt. Hierbei wird die Funktionsweise der verschiedenen Runlevel und die Start-Stop-Scripte in /etc/rc*.d/ und /etc/init.d/ erklärt.
Außerdem wird das Thema syslog bzw. "Wie erzeuge ich eine eigene Logdatei mit syslogd?" anhand des Beispielscriptes gestreift.

Inhalt

- Das Beispielscript getparent
(http://www.linuxforen.de/forums/showpost.php?p=1469774&postcount=2)
- Das Startscript für getparent (http://www.linuxforen.de/forums/showpost.php?p=1469775&postcount=3)

- Verlinkung des Startscripts für die einzelnen Runlevel (http://www.linuxforen.de/forums/showpost.php?p=1469778&postcount=4)

musketaquid
13.12.06, 00:16
Wem ist das nicht schon mal passiert?
Die CPU dümpelt gemütlich for sich hin und plötzlich, ohne Grund, fängt die Platte an zu werkeln, auf dem Monitor liegt die CPU-Auslastung bei ca. 90%. Da schaut man schnell mal eben mit top nach und meistens zeigt sich, dass find oder sort dafür verantwortlich sind. Aber um herauszufinden wer genau diese Prozesse ausgeführt hat, ist die Zeit zu knapp, denn kurz darauf ist schon alles wieder beim Alten.

Genau hier setzt das Beispielscript an. Es soll im Hintergrund lauschen ob find oder sort den Dateibaum durchforsten und wenn dem so ist, deren Elternprozesse herausfinden und alle Informationen in eine Logdatei ablegen.

Das Script heisst getparent

#!/bin/bash
#
# getparent [Prozess]:
#
# lauscht auf Prozesse, die als Parameter gegeben wurden,
# listet deren Eltern und schreibt sie in eine Logdatei.
#
#
# Das Kommando um in die Logdatei zu schreiben
logcmd="logger -p local0.notice -t GETPARENT"

# Warten wir bis sich was tut
while true ; do
for i in $* ; do
if [ $(pidof $i) ] ; then

# Ein Prozess existiert, also nageln wir ihn fest
ppid=$(ps -C $i -o ppid=)
pname=$(ps -p $ppid -o comm=)

# Testen, ob die Variablen auch Werte enthalten
if [ -z $ppid ] || [ -z $pname ] ; then
break
fi

# Ist alles ok, dann wird in die Logdatei geschrieben
echo -n "Der Elternprozess von $i ist $pname" | $logcmd

# Solange es den Prozess gibt, gehen wir schlafen
while [ $(pidof $i) ] ; do
sleep 0.5
done
fi
done
# In dieser Zeit kann uns einiges durch die Lappen gehen,
# aber wir sind nur auf grosse Fische aus :)
sleep 0.5
done

Um mit dem Befehl

logger -p local0.notice -t GETPARENT
in eine Logdatei schreiben zu können, muss die Datei erst mit syslogd erzeugt werden.
Hierzu wird in der Datei /etc/syslog.conf folgende Zeile eingefügt:

local0.* /var/log/getparent.log
Wichtig!
Syslogd muss noch neu gestartet werden:

/etc/init.d/syslogd restart

Jetzt braucht es nur noch ein schönes Startscript, damit aus getparent ein echter Daemon wird.

musketaquid
13.12.06, 00:58
Im Startscript /etc/init.d/getparentd wird der Befehl start-stop-daemon benutzt um getparent zu starten.

Hier das Startscript getparentd

#! /bin/sh -e

# Ist das Script auch da, wo es sein soll
test -x /usr/sbin/getparent || exit 0

gpcommand="getparent find sort"

case "$1" in
start)
echo -n "Starte Daemon getparent: "
start-stop-daemon --start --quiet --pidfile /var/run/getparent.pid --make-pidfile --background --exec /usr/sbin/$gpcommand
echo "fertig."
;;
stop)
echo -n "Stoppe Daemon getparent: "
start-stop-daemon --stop --quiet --pidfile /var/run/getparent.pid
echo "fertig."
;;
restart)
$0 stop
sleep 1
$0 start
;;
*)
echo "Usage: /etc/init.d/getparentd {start|stop|restart}"
exit 1
esac

exit 0

Fall "start"

Die Option --background schickt getparent in den Hintergrund.
Mit der Option --make-pidfile wird eine Datei angelegt, die die ProzessID von getparent enthält. --pidfile legt die Datei fest.
Und die Option --exec sagt start-stop-daemon, wo getparent zu finden ist.

Fall "stop"

Durch die vorher anglegte "pidfile" ist es einfach getparent wieder zu stoppen :)


Anhang


Ich hänge getparent und das dazugehörige Startscript getparentd dem Beitrag an.

Nach dem entpacken müssen die Scripte in die jeweiligen Ordner verschoben werden.

mv getparent /usr/sbin && mv getparentd /etc/init.d
Nun müsste sich der Daemon manuell starten und stoppen lassen.

Test


Der Daemon kann nun mit hilfe des Startscripts erst einmal manuell gestartet werden.

/etc/init.d/getparentd start

Wenn alles geklappt hat, dann sollte dieser Befehl Informationen über den laufenden Daemon anzeigen.
ps -l -p $(cat /var/run/getparent.pid)
Nun kann "find" einmal die Festplatte durchsuchen, mal sehen ob der Daemon auch das leistet, was er soll ;)

find /
Dann sollte in /var/log/getparent.log etwa folgendes stehen:

"Nov 23 02:33:27 solvejg GETPARENT: Der Elternprozess von find ist bash"Das hier gross geschriebene "GETPARENT" ist das Label, das mit dem "logcmd" mitgegeben wurde
logger -p local0.notice -t GETPARENT


Damit der Daemon nicht immer manuell gestartet werden muss, müssen nur noch Links für die Runlevel erzeugt werden.

musketaquid
13.12.06, 01:42
Der Daemon soll nun automatisch gestartet werden.

Runlevel

Runlevel 1 ist der Single User Mode. Den Daemon hier zu starten wäre unsinnig.
Runlevel 2 bis 5 sind Multi User Modes, hier sollte er gestartet werden. Sagen wir, nur in Runlevel 2 und sonst nirgends.
Runlevel 6 und 0 sind für den Reboot bzw. Shutdown des Systems verantworlich. Hier muss getparent auf jeden Fall gestoppt werden.

Für jedes Runlevel gibt es einen Ordner, wo die Links abgelegt werden.
Der Ordner ist /etc/rc1.d für Runlevel 1 und /etc/rc2.d für Runlevel 2 usw..

Weiter Informationen zum Thema Runlevel (http://debiananwenderhandbuch.de/startstop.html)


Aufbau eines Links

Zum Beispiel hat der Daemon syslogd ein Startlink in /etc/rc2.d


ls -l /etc/rc2.d/*sys*

... /etc/rc2.d/S10sysklogd -> ../init.d/sysklogd
Der Name des Links besteht aus einem Buchstaben, einer zweistelligen Zahl und dem eigentlichen Namen.
Der erste Buchstabe kann entweder S oder K sein. S bedeutet, dass das Script, auf das der Link verweist, mit der option "start" aufgerufen wird und K, dass das Script mit "stop" als ersten Parameter aufgerufen wird.
Die zweistellige Zahl, im Fall von Syslog ist es 10, bestimmt die Reihenfolge, in der die Links ausgeführt werden.
Also ein Link mit S10 als Initiator wird vor einem S40iger gestartet. Genauso wird ein K99 Link als letztes gestoppt.
Alles klar soweit?


Anlegen der Links

Um getparentd in Runlevel 2 zu starten und in allen Anderen zu stoppen, legt man folgende Links an:

Startlink

ln -s /etc/init.d/getparentd /etc/rc2.d/S99getparentd
Killlinks

ln -s /etc/init.d/getparentd /etc/rc1.d/K00getparentd
ln -s /etc/init.d/getparentd /etc/rc3.d/K00getparentd
ln -s /etc/init.d/getparentd /etc/rc4.d/K00getparentd
ln -s /etc/init.d/getparentd /etc/rc5.d/K00getparentd
ln -s /etc/init.d/getparentd /etc/rc6.d/K00getparentd
ln -s /etc/init.d/getparentd /etc/rc0.d/K00getparentd
Wenn nun Runlevel 2 betreten wird, startet getparent. Wechselt man zu Runlevel 1, 3, 4, 5, 6 oder 0, dann wird getparent gleich als erstes gestoppt, weil in den dazugehörigen Ordnern die K00getparentd Links liegen.

Wem das zu viel Tipparbeit ist, der hat Recht!
Debian bietet einen Befehl der einem die Tipparbeit abnimmt.

update-rc.d getparentd start 99 2 . stop 00 0 1 3 4 5 6 .
Und schon hat man alle Links mit einem Befehl angelegt.
Toll! Und warum hat er das nicht gleich gesagt?
Müssen wir denn nicht erst laufen, lernen bevor wir die 100m in 10s sprinten? ;)


ENDE

Nach einigen Tagen Laufzeit sollte dann eine schöne Logdatei entstehen.
So siehts bei mir dann aus:

Dec 5 16:39:36 solvejg GETPARENT: Der Elternprozess von sort ist sh
Dec 7 15:16:15 solvejg GETPARENT: Der Elternprozess von sort ist sh
Dec 8 06:25:41 solvejg GETPARENT: Der Elternprozess von sort ist updatedb
Dec 9 06:25:41 solvejg GETPARENT: Der Elternprozess von sort ist updatedb
Dec 9 16:04:40 solvejg GETPARENT: Der Elternprozess von sort ist sh
Dec 10 06:01:23 solvejg GETPARENT: Der Elternprozess von find ist soffice
Dec 12 20:09:50 solvejg GETPARENT: Der Elternprozess von sort ist sh
Dec 12 20:32:56 solvejg GETPARENT: Der Elternprozess von find ist udev.postinst

Viel Spass beim Daemon schreiben!