Ich habe einige Tage nach einer einfachen Möglichkeit gesucht, meine Java Programme als Daemon auf Debian Linux zu starten. Es gibt einiges an Scripten für SuSe und davon auch Portierungen auf Debian. Allerdings fand‘ ich diese Implementierungen immer unnötig kompliziert und unübersichtlich.
Gestern bin ich endlich auf eine einfache und klar programmierte Lösung gestossen. Ein einfacher Wrapperskript der alle benötigten Funktionen unterstützt. Der Skript ist von 2009 läuft aber noch einwandfrei. Allerdings ist er nicht auf Debian spezialisiert und ist für die KSH geschrieben. Ich bin mal alles durchgegangen und habe einige Anpassungen gemacht. Herausgekommen ist folgende Debian interpretation:
#! /bin/sh ### BEGIN INIT INFO # Provides: skeleton # Required-Start: $remote_fs $syslog $network # Required-Stop: $remote_fs $syslog $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Java Daemon Script # Description: This file should be used to construct scripts to be # placed in /etc/init.d. ### END INIT INFO # Author: Jens Heuschkel <jens@3und20.eu> # Do NOT "set -e" # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin APP_NAME="MyApp" APP_LONG_NAME="My App Server" #the location of the pid files. PIDDIR="/var/run" PIDFILE="${PIDDIR}/${APP_NAME}.pid" TIMESTAMP=$( date +%Y%m%d_%H%M%S ) #number of seconds to wait after starting up. WAIT_AFTER_STARTUP=2 #the location of the log files LOG_DIR="/var/log" STDOUT="${LOG_DIR}/${APP_NAME}.stdout.log" #PURGE_EXPRESSION="-mtime +2" PURGE_EXPRESSION="${LOG_DIR}/${APP_NAME}*" HEAPSIZE_INIT=16 HEAPSIZE_MAX=100 VMARGS="-Xms${HEAPSIZE_INIT}M -Xmx${HEAPSIZE_MAX}M -verbose:gc" MAINCLASS="com.wordpress.jensheuschkel.MyApplication" JARFILE="MyApp.jar" ARGS="" JAVA_COMMAND="/usr/bin/java" # Startup with Classpath #START_COMMAND="${JAVA_COMMAND} $VMARGS $MAINCLASS $ARGS" # Startup with jar START_COMMAND="${JAVA_COMMAND} $VMARGS -jar ${JARFILE} ${ARGS}" #----------------------------------------------------------------------------- # Do not modify anything beyond this point #----------------------------------------------------------------------------- checkroot() { if [[ $EUID -ne 0 ]]; then echo "This script must be run as root" 1>&2 exit 1 fi } getpid() { pid="" if [ -f "$PIDFILE" ] then if [ -r "$PIDFILE" ] then pid=`cat "$PIDFILE"|cut -d: -f1` host=`cat "$PIDFILE"|cut -d: -f2` currhost=`hostname` if [ "$host" != "$currhost" ] then echo "You are on the wrong host. $APP_LONG_NAME runs on $host." exit 1 fi if [ "X$pid" != "X" ] then kill -0 $pid > /dev/null 2>&1 if [ $? -ne 0 ] then # Process doesn't exist, so remove pidfile rm -f "$PIDFILE" echo "Removed stale pid file: $PIDFILE" pid="" fi fi else echo "Cannot read $PIDFILE." exit 1 fi fi } #tests if the pid is alive testpid() { kill -0 $pid > /dev/null 2>&1 if [ $? -ne 0 ] then # Process is gone so remove the pid file. rm -f "$PIDFILE" pid="" fi } start() { echo "Starting $APP_LONG_NAME..." getpid if [ "X$pid" = "X" ] then if [ -s $STDOUT ] then #backup current file mv $STDOUT $STDOUT.sav.${TIMESTAMP} fi echo CLASSPATH is $CLASSPATH > $STDOUT echo ${START_COMMAND} >> $STDOUT nohup ${START_COMMAND} >> $STDOUT 2>&1 & echo $!:`hostname` > $PIDFILE else echo "$APP_LONG_NAME is already running." exit 1 fi # Sleep for a few seconds to allow for intialization if required # then test to make sure we're still running. i=0 while [ $i -lt $WAIT_AFTER_STARTUP ] do sleep 1 i=`expr $i + 1` done if [ $WAIT_AFTER_STARTUP -gt 0 ] then getpid if [ "X$pid" = "X" ] then echo "WARNING: $APP_LONG_NAME may have failed to start." exit 1 else echo "running ($pid)." fi else echo "" fi } stopit() { echo "Stopping $APP_LONG_NAME..." getpid if [ "X$pid" = "X" ] then echo "$APP_LONG_NAME was not running." else # Running so try to stop it. kill $pid if [ $? -ne 0 ] then echo "Unable to stop $APP_LONG_NAME." exit 1 fi # If it has not stopped in 10 tries, forcibly kill it savepid=$pid CNT=0 TOTCNT=0 while [ "X$pid" != "X" ] do # Show a waiting message every 5 seconds. if [ "$CNT" -lt "5" ] then CNT=`expr $CNT + 1` else echo "Waiting for $APP_LONG_NAME to exit..." CNT=0 fi if [ $TOTCNT -gt 11 ] then echo "Killing by force (kill -9)" kill -9 $pid fi TOTCNT=`expr $TOTCNT + 1` sleep 1 testpid done pid=$savepid testpid if [ "X$pid" != "X" ] then echo "Failed to stop $APP_LONG_NAME." exit 1 else echo "Stopped $APP_LONG_NAME." fi fi } purge() { # pcmd="find $LOG_DIR -follow -type f $PURGE_EXPRESSION -print -exec rm -f {} +" pcmd="rm -f ${PURGE_EXPRESSION}" echo "Running purge: $pcmd" $pcmd } alert() { if [ "X$EMAIL" != "X" ] then echo "$APP_LONG_NAME is not running on `hostname`. Please check and restart." \ | mailx -s "`hostname`: $APP_LONG_NAME is not running" "$EMAIL" echo "Sent alert to $EMAIL" fi } status() { getpid if [ "X$pid" = "X" ] then echo "$APP_LONG_NAME is not running." alert exit 1 else echo "$APP_LONG_NAME is running (PID:$pid)." exit 0 fi } dump() { echo "Dumping $APP_LONG_NAME..." getpid if [ "X$pid" = "X" ] then echo "$APP_LONG_NAME is not running." else kill -3 $pid if [ $? -ne 0 ] then echo "Failed to dump $APP_LONG_NAME." exit 1 else echo "Dumped $APP_LONG_NAME." fi fi } #################### checkroot case "$1" in 'start') start ;; 'stop') stopit ;; 'restart') stopit start ;; 'status') status ;; 'dump') dump ;; 'purge') purge ;; *) echo "Usage: $0 { start | stop | restart | status | dump | purge }" exit 1 ;; esac exit 0
Die VM Einstellungen sind für das Rapberry Pi und sollten noch angepasst werden. Es wird auch nicht gecheckt ob JAVA installiert ist aber das kann man ja im Install-Skript des Servers machen 😉
Quelle:
http://fahdshariff.blogspot.de/2009/09/unix-wrapper-script-for-java.html
Hallo Jens,
Dein Script ist genau das, was ich gesucht habe :-). Ich habe einen Server-Dienst derzeit nur in Java verfügbar und möchte ihn auf dem Raspberry Pi starten lassen.
Bisher funktioniert alles ganz gut, nur erhalte ich eine Fehlermeldung in Zeile 56: [[: not found.
Hat es einen Grund, warum Du hier zwei eckige Klammern benutzt?
Grüße,
Siegmund
Hi,
ja das hat irgend einen Grund den ich aber vergessen habe:D. Wie im Artikel beschrieben, ist das eine Adaption von einem anderen Skript; vllt. findest du in der Quelle einen Hinweis warum dort zwei Klammern nötig sind. Alternativ kannst du mal in der Bash Syntax nachsehen 😉
Allerdings ist mir der Fehler auf dem Pi auch schon unter gekommen. Das liegt daran, dass das Raspbian scheinbar diese Variable nicht unterstützt. Mit folgendem Code sollte es laufen:
Hallo Jens,
1)
habe das schon getan ;-). Allerdings ist es noch sicherer, Apostrophe zu verwenden:
if [ „$(id -u)“ -ne „0“ ]
2)
Damit das script /usr/bin/service mit dem Dienst zurechtkommt, müssen noch ein paar weitere Änderungen gemacht werden:
Zunächst mal habe ich die InitFunctions eingebunden:
. /lib//lsb/init-functions
Dann habe ich nur die PID ins PID-File geschrieben, nicht den Hostnamen und dann bei getpid() die Prüfung vereinfacht::
pid=’cat „$PIDFILE“
(Ich sehe das zum ersten Mal – wofür ist die Host-Prüfung überhaupt notwendig?)
Analog dazu wird bei start() natürlich nicht mehr der Hostname miteingetragen:
echo $! > $PIDFILE
Die Funktion status() wird gar nicht benötigt, das kann man ebenfalls machen mit:
status_of_proc -p $PIDFILE $JAVA_COMMAND $APP_NAME && exit 0 || exit $?
Zu guter Letzt sollten in der letzten case-Anweisung die Hochkommas entfernt werden, da ansonsten „service –status-all“ fehlschlägt:
’status)‘ wird also zu status)
usw.
Mit diesen Änderungen funktionieren nun auch
service –status-all
service MyJavaDaemon start
service My JavaDaemon stop
service MyJavaDaemon status
usw.
Siegmund