initscripts for 360Radar’s ADS-B uploader

360Radar.co.uk is a browser-based ADS-B and MLAT aircraft tracking system.

I knocked together an initscript for Linux users which should work with most Debian-based Linux distros (inc. Raspbian on the Raspberry Pi).

This assumes you are running as a user with root-level permissions (if not, sudo is your friend), a level of familiarity with the Linux command line, permissions, etc.

Install mono

Follow the Install Mono instructions in the official 360Radar installation instructions:

http://radar.lowflyingwales.co.uk/360radar-adsb-uploader-instructions-raspberry-pi/

Create a new user to run the ADS-B uploader

Rather than run the uploader as an existing user (e.g. pi), we’ll create a new user to run it away from our normal login user.

I’m creating a new user called (rather unimaginatively) adsbfilter, with a home directory of /opt/adsbfilter.

useradd -m -g nogroup -d /opt/adsbfilter adsbfilter

Change to the new user and download the uploader

su – adsbfilter

Now we’re in the new user environment, we need to download the uploader. Back to the official installation instructions:

wget http://radar.lowflyingwales.co.uk/files/adsb/rpi/AdsbFilter-1.0.17.tgz

Extract the compressed tarball you download:

tar xzf AdsbFilter-1.0.17.tgz

This’ll create a new directory AdsbFilter containing the ADS-B uploader.

Create a wrapper script

We’ll use a wrapper script to restart the ADS-B uploader unless it’s stopped cleanly and deliberately. This will automatically restart it in the event of a segfault, which seems to happen from time to time with the nightly mono builds.

Create adsbfilter.sh in /opt/adsbfilter/AdsbFilter (or modify with your chosen path):

nano -w /opt/adsbfilter/AdsbFilter/adsbfilter.sh

#!/bin/bash

while :; do
        /usr/bin/mono AdsbFilter.exe "$@"
        result=$?

        if [ $result -eq 58 ]; then
                echo "adsbfilter terminated normally"
                break
        else
                echo "adsbfilter terminated with return code: $result"
        fi
        sleep 5
        echo "restarting adsbfilter..."
done

Set the executable bit on the wrapper and the program itself:

cd /opt/adsbfilter/AdsbFilter

chmod +x adsbfilter.sh AdsbFilter.exe

Now come out of our adsbfilter user environment:

exit

Create the initscript

We’ll create a standard Debian initscript in /etc/init.d/adsbfilter:

#!/bin/bash
### BEGIN INIT INFO
# Provides:          adsbfilter
# Required-Start:    $remote_fs
# Required-Stop:     $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: ADSB Filter
# Description:       Sends ADS-B messages to 360radar.co.uk
### END INIT INFO

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="adsbfilter"
NAME=adsbfilter
DAEMON=/opt/adsbfilter/AdsbFilter/adsbfilter.sh
ARGS=""
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# work out daemon args

# sanitize missing settings
badconfig=""
[ -z "$START_CLIENT" ] && START_CLIENT=no
[ -z "$RUN_AS_USER" ] && badconfig="$badconfig RUN_AS_USER"
[ -z "$INPUT_HOST" ] && INPUT_HOST=localhost
[ -z "$INPUT_TYPE" ] && INPUT_TYPE=dump1090
[ -z "$LAT" ] && badconfig="$badconfig LAT"
[ -z "$LON" ] && badconfig="$badconfig LON"
[ -z "$EMAIL" ] && badconfig="$badconfig EMAIL"
[ -z "$LIGHTWEIGHT" ] && LIGHTWEIGHT=no

ARGS="--input-host $INPUT_HOST --input-type $INPUT_TYPE --lat $LAT --lon $LON --email $EMAIL"

if [ "$LIGHTWEIGHT" == "yes" ]; then
    ARGS="$ARGS --lightweight"
fi

ARGS="$ARGS $EXTRA_ARGS"
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
        # Return
        #   0 if daemon has been started
        #   1 if daemon was already running
        #   2 if daemon could not be started

        if [ "x$START_CLIENT" != "xyes" ]; then
            log_warning_msg "Not starting $NAME daemon, disabled via /etc/default/$NAME"
            return 2
        fi

        if [ -n "$badconfig" ]; then
            log_warning_msg "Not starting $NAME daemon, missing configuration options ($badconfig)"
            return 2
        fi

        start-stop-daemon --start --quiet --pidfile $PIDFILE --user "$RUN_AS_USER" --startas $DAEMON --test > /dev/null \
                || return 1

        start-stop-daemon --start --nicelevel 5 --quiet --pidfile $PIDFILE --user "$RUN_AS_USER" --chuid "$RUN_AS_USER" --make-pidfile --background --no-close --startas $DAEMON -- \
                $ARGS >>$LOGFILE 2>&1 \
                || return 2
        sleep 1
}

#
# Function that stops the daemon/service
#
do_stop()
{
        # Return
        #   0 if daemon has been stopped
        #   1 if daemon was already stopped
        #   2 if daemon could not be stopped
        #   other if a failure occurred
        start-stop-daemon --stop --retry=TERM/30/KILL/5 --pidfile $PIDFILE --user "$RUN_AS_USER"
        RETVAL="$?"
        [ "$RETVAL" = 2 ] && return 2
        sleep 1
        # Many daemons don't delete their pidfiles when they exit.
        rm -f $PIDFILE
        return "$RETVAL"
}

case "$1" in
  start)
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
        do_start
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
  stop)
        [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
        do_stop
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
  status)
        status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
        ;;
  restart|force-reload)
        log_daemon_msg "Restarting $DESC" "$NAME"
        do_stop
        case "$?" in
          0|1)
                do_start
                case "$?" in
                        0) log_end_msg 0 ;;
                        1) log_end_msg 1 ;; # Old process is still running
                        *) log_end_msg 1 ;; # Failed to start
                esac
                ;;
          *)
                # Failed to stop
                log_end_msg 1
                ;;
        esac
        ;;
  *)
        echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
        exit 3
        ;;
esac

:

If you decided to use a different username or path, change the following line accordingly:

DAEMON=/opt/adsbfilter/AdsbFilter/adsbfilter.sh

Make it executable:

chmod +x /etc/init.d/adsbfilter

Create the settings file

Create the following in /etc/default/adsbfilter:

# Start the client?
START_CLIENT="yes"

# System user to run as.
RUN_AS_USER="adsbfilter"

# Logfile to log to
LOGFILE="/var/log/adsbfilter.log"

# Input receiver type (dump1090, sbs)
INPUT_TYPE="dump1090"

# Input host
INPUT_HOST="localhost"

# Latitude of the receiver, in decimal degrees
LAT="<your latitude>"

# Longitude of the receiver, in decimal degrees
LON="<your longitude>"

# Email address for login
EMAIL="<your email>"

# Ignores some ADSB messges to trade off CPU
# usage in return for performance
LIGHTWEIGHT="yes"

# Other arguments to pass to adsbfilter
EXTRA_ARGS=""

Modify the various parameters as required. At the very least, you’ll need latitude, longitude and email.

Finalising the install

We now need to tell the system about the new script:

systemctl daemon-reload

And add it to the autostart runlevels:

update-rc.d adsbfilter defaults

And finally, start it manually for the first time:

service adsbfilter start

Check to make sure things started properly by viewing /var/log/adsbfilter.log

Optional: add a logrotate snippet

The ADS-B uploader logs its activity every second, so the adsbfilter.log file can quickly become large. We can use logrotate to trim it periodically and archive off a few days of historical data.

Create /etc/logrotate.d/adsbfilter:

/var/log/adsbfilter.log {
  rotate 7
  daily
  delaycompress
  compress
  copytruncate
}

And that’s it!