25 January 2015

Creating Centos or Redhat init scripts

Init scripts are used to start and stop daemon processes on Linux systems. In turns out, that like most things in Linux, they are pretty simple. Following a few rules allows you to quickly create a script that plays well with how the system starts up and shuts down.

There is a pretty good guide that explains all the parts of the init scripts in much more detail that I will repeat here.

Things an Init Script Should Do

Script Location and Naming

Your init script should be given the same name as the process you are tying to start and it should be stored in /etc/rc.d/init.d. For example, if you are creating an init script for a process called flume, you should create a file /etc/rc.d/init.d/flume and set its permissions to 755.

Once you do this, you can use the service command start and stop the service, for example:

# /etc/rc.d/init.d/testservice
echo "executed the service start script"

$ service testservice start
executed the service start script

Manage /var/lock/subsys

For a few reasons, an init script should create a lock file in /var/lock/subsys/ upon starting and clear it when stopped. If the OS is shutdown, reboot or the run level is changed, these lock files are used to determine which processes to stop and start.

Create a Pidfile

It should write a pidfile (ie a file containing the PID of the parent process of the service) into /var/run. What I found is that if the process runs as a user other than root, the user starting the process probably won't have permission to write into /var/run. If that is the case, you can create a sub-directory, and store the pidfile there - /var/run//.pid.

Chkconfig Header

For Redhat systems, all init scripts should contain a header line for chkconfig, normally it looks something like this:

# chkconfig: - 20 80

This means the script is off by default on all run levels, which can be changed using the chkconfig utility.

Additionally, and chkconfig description line should be included:

# description: This is a description for my service. Multiple lines \
#              should be ended with a backslash as shown.

The library functions

On Redhat (and Centos systems), there are a few library functions that you should include in any init script. They are stored in /etc/rc.d/init.d/functions, and should be included into the init script:

# source function library
. /etc/rc.d/init.d/functions

This library provides 4 functions.

daemon

Used to start a process that correctly daemonizes itself. Interestingly, the daemon function does not write a pidfile for the process it starts. I think it expects the process to create its own pidfile. It takes a few options in a command line like format, including the program to start and any options to pass to the program, for instance:

daemon --user=httpd --pidfile=/var/run/httpd.pid /usr/local/bin/<service> <any service start options>

The user switch is only required if the process does not run as root. The pidfile parameter is also optional - it does not actually create a pidfile for the process that is started.

killproc

Used to shutdown (or kill) a running process. Generally you pass it the pid file of the process and it shuts it down.

killproc -p /var/run/process.pid /usr/local/bin/process [-signal]

pidofproc

Can be used to find the pid of the procedure, if it is running:

pidofproc -p /var/run/process.pid /user/local/bin/process

status

Tests to see if the process is running or not:

status  -p /var/run/process.pid /user/local/bin/process

Init Script Template

Putting all these points together, gives a fairly generic init script template (taken directly from the guide I mentioned earlier:

#!/bin/sh
#
# <daemonname> <summary>
#
# chkconfig:   - 20 80
# description: <description, split multiple lines with \
#              a backslash>

# Source function library.
. /etc/rc.d/init.d/functions

exec="/path/to/<daemonname>"
prog="<service name>"
config="<path to major config file>"

[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog

lockfile=/var/lock/subsys/$prog

start() {
    [ -x $exec ] || exit 5
    [ -f $config ] || exit 6
    echo -n $"Starting $prog: "
    # if not running, start it up here, usually something like "daemon $exec"
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    # stop it here, often "killproc $prog"
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    stop
    start
}

reload() {
    restart
}

force_reload() {
    restart
}

rh_status() {
    # run checks to determine if the service is running or use generic status
    status $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}


case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
        restart
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
esac
exit $?
blog comments powered by Disqus