Crontab + Bashscript + Perlscript -> Defunct

seraphim

New Member
Hallo, ich hab da ein Problem mit einem Crontab für ein Bashscript dass mir ein Perlscript am Leben halten soll.

Dateien:
perldatei.pl
CHMod: 644
Inhalt:
http://pastebin.com/mLxkt6fP

Bash Script (nicht meines, habe das von UnrealIRCd genommen und ein wenig abgeändert)
check.in
CHMod: 755
Code:
#!/bin/sh

MAIL=root

# The path to the binary
ircdexe="perl -T /pfad/perldatei.pl"

# The path to the pid file
ircdname="/pfad/pid.pid"

if test -r $ircdname; then
  # there is a pid file -- is it current?
  ircdpid=`cat $ircdname`
  if `kill -CHLD $ircdpid >/dev/null 2>&1`; then
    # it's still going
    # back out quietly
    exit 0
  fi
  echo "Policyd Crontab notice:"
  echo ""
fi
echo ""
echo "Couldn't find the policy daemon running.  Reloading it..."
echo ""
$ircdexe

Crontab:
0,5,10,15,20,25,30,35,40,45,50,55 * * * * /pfad/check

Problemstellung:
Wenn ich das Script check selber ausführe via Putty funktioniert alles wunderbar.
Wenn ich den Perl Prozess kille und auf die Ausführung des Cronscriptes warte, dann passiert folgendes:
-das Perlscript wird gestartet und läuft, schreibt aber nicht die PID in die .pid Datei
-es gibt einen Defunct, Ausgabe von ps ux:
Code:
user   8541  0.0  0.0      0     0 ?        Zs   17:50   0:00 [check] <defunct>
user   8544  0.0  0.1   5616  1704 ?        S    17:50   0:00 /usr/sbin/sendmail -i -FCronDaemon -oem user
user   8545  0.0  0.1   5608  1696 ?        S    17:50   0:00 /usr/sbin/postdrop -r
user   8552  0.0  0.2   4672  2320 ?        Ss   17:50   0:00 perl -T /pfad/perldatei.pl

Das seltsame ist, dass danach ausgeführte Crontabs mit dem Script mir EMails schicken mit folgendem Inhalt:
Policyd Crontab notice:
Couldn't find the policy daemon running. Reloading it...

bind: Address already in use at /pfad/perldatei.pl line 51.

was ja auch nachvollziehbar ist, da das Perlscript wunderbar läuft.

Ich bitte um Hilfe!

PS: Die Pfade und Usernamen habe ich geändert, innerhalb der Scripte und Dateien sind sie alle korrekt.
 
Last edited by a moderator:
Bei der Ausführng durch cron hast Du nicht die gleiche Umgebung wie an der Shell.
Möglicherweise werden von Perl ja bestimme Module oder Bibliotheken nicht gefunden.
 
Es stimmt schon mit der "nicht die gleiche Umgebung".
Du bist nämlich im falschen Verzeichnis.
Du testest wahrscheinlich in der Console genau in dem Verzeichnis. Und damit klappt es.
Das Cronscript startet aber mit einem anderen Verzeichnis. Es findet zwar alle Dateien, da jeweils /pfad/ davor steht, aber die Pid-Datei wird ohne Pfad-Angabe geschrieben. :eek:

Lösung:
Entweder auch die Pid-Datei mit /pfad/ ergänzen, oder im Cronjob vorher ins Verzeichnis wechseln.

huschi.
 
Aber nur beim Lesen. Geschrieben wird einfach in das aktuelle Verzeichnis. (Siehe Pastebin-Link.)

huschi.
 
Ich hab den Pfad in der Perldatei absolut gesetzt, der Perl Daemon schreibt nun die PID richtig rein, an dem Defunct hat sich nichts geändert.
 
Aber die Email hat sich geändert, oder?

Schau Dir mal den Prozess-Baum an (entweder mit pstree oder ps auxf).
Falls der Defunc-Prozess einen Child hat (mein Tipp), dann liegt es daran.
Entweder löst sich der Child vom Vater oder Du musst damit leben.

huschi.
 
Kann zwar zum Problem nicht helfen, was mir aber auffällt:
Wenn du das eh alle 5 Minuten ausführen willst, warum so kompliziert?
"0,5,10,15,20,25,30,35,40,45,50,55" könnte man auch mit */5 machen.
Code:
*/5 * * * * cd /pfad && ./check
 
Code:
root      3479  0.0  0.0   3456   876 ?        Ss    2010   0:14 /usr/sbin/cron
root     18000  0.0  0.1   7504  1732 ?        S    20:35   0:00  \_ /USR/SBIN/CRON
user  18001  0.0  0.0      0     0 ?        Zs   20:35   0:00      \_ [policydchk] <defunct>
user  18005  0.0  0.1   5616  1700 ?        S    20:35   0:00      \_ /usr/sbin/sendmail -i -FCronDaemon -oem user
user  18008  0.0  0.1   5608  1700 ?        S    20:35   0:00          \_ /usr/sbin/postdrop -r

Childs sind also nur sendmail und postdrop...
 
Last edited by a moderator:
Die Standard-I/O-Kanäle müssen noch geschlossen werden. Ich nutze für einen Daemon immer folgenden Code:
Code:
#
# Become a daemon
#
open(STDIN, '/dev/null')    || die "Can't read from /dev/null: $!";
open(STDOUT, '>>/dev/null') || die "Can't write to /dev/null: $!";
open(STDERR, '>>/dev/null') || die "Can't write to /dev/null: $!";
defined(my $pid = fork())   || die "Can't fork: $!";
exit if $pid;
setsid                      || die "Can't start a new session: $!";

Statt der Suche nach einer PID im Shell-Script (es ist zwar unwahrscheinlich, aber unter der PID könnte auch ein anderer Prozeß laufen), nutze ich im Daemon ein Lock auf eine Datei, was beim Prozeßende automatisch verschwindet. Damit kann der Daemon ohne Shell-Script einfach periodisch von Cron neu gestartet werden und das Lock garantiert, dass maximal eine Instanz läuft:

Code:
#
# Use a lockfile for sychronization.  We put an exclusive lock on the
# lockfile, which makes a second process silently fail.
#
my $lockfile = "/var/lock/XXX.lock";

open(LOCKFILE, ">$lockfile") || die "Can't write to lockfile: $!";
flock(LOCKFILE, 6) || exit 1;   # Another process is running

Den Handle LOCKFILE darf man dann nicht mehr schließen, solange das Programm läuft.
 
Back
Top