Java Server als Daemon auf Debian Linux

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

Advertisements

Bash IF Conditions

Jaja schon wieder Bash :DIch vergesse einfach ständig die Syntax und aufschreiben ist das Einzige das ein bisschen hilft.
Mal „unter uns“: Bash ist auch eine der anstrengensten Skriptsprachen überhaupt …

Also diesmal geht es um IF Conditions. Grundsätzlich funtkioniert es wie folgt:

if [ <condition> ]then

elif [ <condition> ]
then

else

fi

Das allein finde ich schon unintuitiv: „elif“ statt „else if“ und then in einer neuen Zeile. Alternativ kann man auch „; then“ in der gleichen Zeile schreiben. Abgeschlossen wird das ganze mit „if“ rückwärts, also „fi“. Aufpassen, denn die Leerzeichen vor und nach den Klammern sind nicht optional!

Nun nun zu den Conditions:

  • [ -e filepath ] wird true wenn die Datei existiert.
  • [ -x filepath ] wird true wenn die Datei existiert und ausführbar ist.
  • [ -S filepath ] wird true wenn die Datei existiert und eine Socket-Datei ist.
  • [ -d filepath ] wird true wenn die Datei existiert und ein Verzeichnis ist.
  • [ -w filepath ] wird true wenn die Datei existiert und schreibbar ist.
  • [ expr1 -a expr2 ] entspricht dem logischen AND (Java: &&)
  • [ expr1 -o expr2 ] entspricht dem lofischen OR (Java: || )
  • [ -n $VARIABLE ] wird true wenn die Varable (also der String) nicht leer ist.
  • [ -z $VARIABLE ] wird true wenn die Varable (also der String) leer ist (Java: „foo“.isEmpty() ).
  • [ $VARIABLE = $VARIABLE2 ] wird true wenn die beiden Variablen gleich sind (Java: „foo“.equals(„foo“) ).
    ACHTUNG: Das funktioniert nur mit Strings und nicht mit Zahlen und ist Case-Sensitiv.
  • [ $VARIABLE -eq $VARIABLE2 ] wird true wenn die beiden Variablen die gleich Zahl enthalten (Java: == ).
  • [ $VARIABLE -lt $VARIABLE2 ] wird true wenn die 1. Variable kleiner ist (Java: < ).
  • [ $VARIABLE -gt $VARIABLE2 ] wird true wenn die 1. Variable größer ist (Java: > ).
  • [ $VARIABLE -le $VARIABLE2 ] wird true wenn die 1. Variable kleiner oder gleich ist (Java: <= ).
  • [ $VARIABLE -ge $VARIABLE2 ] wird true wenn die 1. Variable gößer oder gleich ist (Java: >= ).
  • [ $VARIABLE -ne $VARIABLE2 ] wird true wenn die beiden Variablen ungleich sind (Java: != ).
  • [ ! <condition> ] negiert die condition (Java: ! ).

Es gibt noch einige mehr, aber ich denke das sind die Wichtigsten.

Quellen:
http://wiki.ubuntuusers.de/Shell/Bash-Skripting-Guide_f%C3%BCr_Anf%C3%A4nger
http://www.thegeekstuff.com/2010/06/bash-conditional-expression/

qcow2 Disk Image mounten

Kurzanleitung um eine gcow2 Disk-Image auf Ubuntu LTS 10.04 zu mounten:

Als root, mit einem qcow2-image
modprobe nbd max_part=8
qemu-nbd --connect=/dev/nbd0 db1_old.qcow2
# mount first partition
mount /dev/nbd0p1 /mnt/

wieder freigeben:
umount /mnt/
qemu-nbd --disconnect /dev/nbd0

Quelle: http://blog.loftninjas.org/2008/10/27/mounting-kvm-qcow2-qemu-disk-images/

Raspberry Pi Custom Image

Mir wurde es langsam lästig, bei jeder Raspberry Pi Installation das Keyboardlayout, Timezone usw. einzustellen. Deswegen habe ich mir ein Image mit minimalen Anpassungen geschrieben. Das kann wie gewohnt auf eine SD Karte geschrieben werden (Anleitungen gibt’s auf raspberrypi.org). Nach dem ersten Start würde ich nochmal „rasp-config“ starten und „expand_rootfs“ ausführen. Folgende Einstellungen sind zu erwarten:

  • Location: de_DE.UTF-8
  • Keyboardlayout: Generic 105-Key German
  • Timezone: Europe/Berlin
  • Memory-Split: 240MB für ARM
  • Vorinstallirte Programme: watchdog, vim, htop, cpufrequtils, opendk-7-jre
  • watchdog aktiviert
  • .bashrc für root
  • .vimrc für pi und root
  • sshd Port auf 2224 gesetzt

Und hier der Downloadlink:
2012-09-18-wheezy-raspbian-custom.zip

Image

Auslösungen bei der EOS 7D auslesen.

Ich war heute neugierig wie viele Auslösungen meine gebrauchte 7D denn eigentlich schon hat. Nach kurzer Google-Rescherche hab ich schon mal gelernt, dass die EOS einen Counter dafür hat und Canon den kostenpflichtig auslesen kann.

Das muss natürlich auch kostenlos gehen !

Ein wenig später bin ich auf einen Blog gestoßen, wo sich ein Artikel dieser Problematik annimmt. Die Lösung ist gphoto2. Das ist eine kostenloses OpenSource Tool, dass die libgphoto2 benutzt. Mit den gängigen Linuxssystemen kann das Problemlos installiert werden. Die 7D wir unter Ubuntu von aus Haus aus erkannt. Also habe ich meine Ubuntu VM (Virtuelle Maschine) gestartet und die 7D angeschlossen.

Der Befehl „gphoto2 –get-config /main/status/shuttercounter“ hat das Geheimnis gelüftet: 101k Auslösungen.

Die 7D ist auf ca 150k Auslösungen ausgelegt. Mit etwas Glück schafft die Kamera bei mir noch 3-4 Jahre.. aber bis dahin habe ich bestimmt schon wieder ein neueres Modell 😀

Motiviert durch den Erfolg habe ich das ganze nochmal mit meiner 350D getestet. Diese scheint aber keinen Counter zu besitzen …

 

Quelle: http://www.sensorart.de/wordpress/?p=305