search by tags

for the user

adventures into the land of the command line

creating your own init.d script

in a previous post i was talking about using an application called supervisor to manage gunicorn processes. in that post i mentioned describing how to create an init.d script for supervisor. the logic in this init.d script can be applied generally, but it uses supervisor as an example

init.d scripts are scripts which allow a root user to manually start and stop a process. on many linux distributions the scripts live inside /etc/init.d/ or /etc/rc.d/init.d/

it might be necessary to have some knowledge of linux run levels to create an init.d script, and so i might do a future post about it, but for now i’ll stick to the init.d script itself.

the script has to follow a certain template; there needs to comments at the very top that specify the name of the service, a description, the run levels and kill order/start order for the service, and other information like where to place the pid file, config file locations, etc. something like this

#!/bin/sh
#
# supervisord        Startup script for supervisord
#
# chkconfig: 2345 85 15
# processname: supervisord
# config: /etc/supervisord.conf
# pidfile: /var/run/supervisord.pid
# description: Supervisor is a client/server system that
# allows its users to monitor and control a
# number of processes on UNIX-like operating
# systems.
#
### BEGIN INIT INFO
# Provides: supervisord
# Required-Start: $local_fs $remote_fs $network
# Required-Stop: $local_fs $remote_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: start and stop supervisord
### END INIT INFO

the rest of it is essentially a bash script, that you can create your own logic with, to determine the conditions for a start or stop or restart, or any other function you would like, such as to check version, reload configs, etc.

you’ll want to declare variables at the top

APP="/usr/bin/supervisord"
PIDFILE="/var/run/supervisord.pid"
LOCKFILE="/var/lock/subsys/supervisord"
RETVAL=0

create some functions

start()
{
  if [ -f $PIDFILE ]
  then
    failure
    echo "Supervisor already running... "
  else
    nohup nice /usr/bin/supervisord -c /etc/supervisord.conf > /dev/null 2>&1 &
    RETVAL=$?
    [ $RETVAL = 0 ] && touch $LOCKFILE
    PID=`/bin/ps -ef | /bin/grep [s]upervisor | /bin/awk '{ print $2 }'`
    echo $PID > $PIDFILE
    success
    echo "Starting supervisord:"
  fi
}

stop()
{
  if [ -f $PIDFILE ]
  then
    killproc -p $PIDFILE $APP
    RETVAL=$?
    [ $RETVAL = 0 ] && rm -f $LOCKFILE $PIDFILE
    success
    echo "Stopping supervisord:"
  else
    failure
    echo "Supervisor is not running... "
  fi
}

then create some function calls and a message to tell the user how to use the script

case "$1" in

  start)
    start
  ;;

  stop)
    stop
  ;;

  status)
    status $APP
  ;;

  restart)
    stop
    start
  ;;

  *)
    echo "Usage: $0 {start|stop|restart|status}"
  ;;

esac

in my example, the logic i used for starting and stopping centers around the existence of a pidfile. on startup, a pidfile is created and placed into a specific location using the pid id of the running supervisor process as its contents. a lockfile is also created to ensure that multiple rogue processes aren’t created. on shutdown, the content of the pidfile, (the pid id) is used to find and kill the process. then the pidfile is removed as well as the lockfile.

there are a few functions used, namely ‘success’, 'failure’, 'status’ and 'killproc’ which come from /etc/init.d/functions. these provide the [OK], [FAILED], 'such and such application is running…’ and ability to find and kill a running process functions. you need to include the 'functions’ file at the beginning of the init.d script in order to use them.

# Source init functions
. /etc/init.d/functions

the script has to go inside /etc/init.d and it must be executable and owned by root. to run it you can do any of

$ sudo /etc/init.d/supervisord start/stop/restart/status
$ sudo /sbin/service supervisord start/stop/restart/status

as root user

$ service supervisord start/stop/restart/status

here’s the full script

#!/bin/sh
#
# supervisord        Startup script for supervisord
#
# chkconfig: 2345 85 15
# processname: supervisord
# config: /etc/supervisord.conf
# pidfile: /var/run/supervisord.pid
# description: Supervisor is a client/server system that
# allows its users to monitor and control a
# number of processes on UNIX-like operating
# systems.
#
### BEGIN INIT INFO
# Provides: supervisord
# Required-Start: $local_fs $remote_fs $network
# Required-Stop: $local_fs $remote_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: start and stop supervisord
### END INIT INFO

# Source init functions
. /etc/init.d/functions

APP="/usr/bin/supervisord"
PIDFILE="/var/run/supervisord.pid"
LOCKFILE="/var/lock/subsys/supervisord"
RETVAL=0

start()
{
  if [ -f $PIDFILE ]
  then
    failure
    echo "Supervisor already running... "
  else
    nohup nice /usr/bin/supervisord -c /etc/supervisord.conf > /dev/null 2>&1 &
    RETVAL=$?
    [ $RETVAL = 0 ] && touch $LOCKFILE
    PID=`/bin/ps -ef | /bin/grep [s]upervisor | /bin/awk '{ print $2 }'`
    echo $PID > $PIDFILE
    success
    echo "Starting supervisord:"
  fi
}

stop()
{
  if [ -f $PIDFILE ]
  then
    killproc -p $PIDFILE $APP
    RETVAL=$?
    [ $RETVAL = 0 ] && rm -f $LOCKFILE $PIDFILE
    success
    echo "Stopping supervisord:"
  else
    failure
    echo "Supervisor is not running... "
  fi
}

case "$1" in

  start)
    start
  ;;

  stop)
    stop
  ;;

  status)
    status $APP
  ;;

  restart)
    stop
    start
  ;;

  *)
    echo "Usage: $0 {start|stop|restart|status}"
  ;;

esac

there you go. this isn’t the only way to do it, but it’s a fairly simple example and should provide you with a good idea of how to make your own.