LSB-ish init script, RFC

Matthew Farrellee mfarrellee+fedora at redhat.com
Fri Feb 15 14:15:45 UTC 2008


While trying to write an LSB init script for the condor package, I ran 
across PackagingDrafts/SysVInitScript [1]. It has a very nice template 
for an init script. But, first, it wasn't quite sufficient for my 
service, and, second, it didn't exactly follow the Initial Actions [2], 
which is nearly verbatim the LSB Core 3.2 Init Script Actions [3].

First, it wasn't sufficient for my service because anyone can run a copy 
of my service. They just have to have their own config file. Think of it 
like having both a system httpd, listening on port 80, and a user httpd, 
listening on port 1134. Both process names can easily be "httpd". This 
is a problem because /etc/init.d/functions' status() uses pidof, which 
can find a user's process and confuse it with a system process. This 
means running "service blah start" can silently fail because the init 
script thinks the service is already running, when only the user's copy 
of the service is running. To get around this I implemented my own 
rh_status, calling it pid_status, that uses a pidfile to determine if 
the service is running.

Second, the template init script doesn't quite follow the Initial Action 
description for "restart". It always calls "stop" even if the service is 
already stopped. It also doesn't always print error messages on errors, 
such as reload when the service is not running or when the executable is 
missing during restart/stop.

Below is a template init script, based on the one already in the wiki, 
that solves the issues above. I'd appreciate feedback on how it could be 
improved. Maybe it could be added to the wiki as an additional template 
for services that create pidfiles when they start.

Best,


matt

[1] http://fedoraproject.org/wiki/PackagingDrafts/SysVInitScript
[2] 
http://fedoraproject.org/wiki/PackagingDrafts/SysVInitScript#head-2a29ef136c4702a14dcf6127e3b7d6ff558817b9
[3] 
http://refspecs.linux-foundation.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html

template.init:
#!/bin/sh
#
# <daemonname> <summary>
#
# chkconfig:   <default runlevel(s)> <start> <stop>
# description: <description, split multiple lines with \
#              a backslash>

### BEGIN INIT INFO
# Provides:
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start:
# Default-Stop:
# Short-Description:
# Description:
### END INIT INFO

# 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
pidfile=/var/run/$prog.pid


start() {
     echo -n $"Starting $prog: "
     # $prog must create proper /var/run/$prog.pid
     # start $prog, often: daemon --pidfile $pidfile $exec
     RETVAL=$?
     echo
     [ $RETVAL -eq 0 ] && touch $lockfile
     return $RETVAL
}

stop() {
     echo -n $"Stopping $prog: "
     # stop $prog, often: killproc -p $pidfile $prog
     RETVAL=$?
     echo
     # also rm -f $pidfile, if $prog doesn't do it itself
     [ $RETVAL -eq 0 ] && rm -f $lockfile
     return $RETVAL
}

reload() {
     echo -n $"Reloading $prog: "
     # tell $prog to reload its config
     RETVAL=$?
     echo
     return $RETVAL
}

force_reload() {
     echo -n $"Reloading $prog: "
     # tell $prog to reload its config, or just restart it
     RETVAL=$?
     echo
     return $RETVAL
}

#
# Determine if a process is running only by looking in a pidfile.
# There is no use of pidof, which can find processes that are not
# started by this script.
#
# ASSUMPTION: The pidfile will exist if the process does, see false
# negative warning.
#
# WARNING: A false positive is possible if the process that dropped
# the pid file has crashed and the pid has been recycled. A false
# negative is possible if the process has not yet dropped the pidfile,
# or it contains the incorrect pid.
#
# Usage: pid_status <pidfile> <lockfile>
# Result: 0 = pid exists
#         1 = pid does not exist, but pidfile does
#         2 = pid does not exist, but lockfile does
#         3 = pidfile does not exist, thus pid does not exist
#         4 = status unknown
#
pid_status() {
     if [ -f $1 ]; then
         # this can fail if we're not privileged
         pid=`cat $1` &>/dev/null
         if [ $? -ne 0 -o -z "$pid" ]; then
	    echo $? $pid
             return 4
         fi

         ps $pid &>/dev/null
         if [ $? -ne 0 ]; then
	    if [ -e $2 ]; then
		return 2
	    fi

             return 1
         fi

         return 0
     fi

     return 3
}


pid_status $pidfile $lockfile
running=$?

if [ "$1" != "status" ]; then
     # Report that $exec does not exist, or is not executable
     [ -x $exec ] || (echo $"$0: error: program not installed" && exit 5)

     # Report that $prog's config does not exist
     [ -f $config ] || (echo $"$0: error: program not configured" && exit 6)

     [ $running -eq 4 ] && echo $"$0: error: insufficient privileges" && 
exit 7
fi

case "$1" in
     start)
	[ $running -eq 0 ] && exit 0
	start
	RETVAL=$?
	;;
     stop)
	[ $running -eq 0 ] || exit 0
	stop
	RETVAL=$?
	;;
     restart)
	[ $running -eq 0 ] && stop
	start
	RETVAL=$?
	;;
     try-restart)
	[ $running -eq 0 ] || exit 0
	stop
	start
	RETVAL=$?
	;;
     reload)
	[ $running -eq 0 ] || (echo $"$0: error: $prog is not running" && exit 7)
	reload
	RETVAL=$?
	;;
     force-reload)
	[ $running -eq 0 ] || (echo $"$0: error: $prog is not running" && exit 7)
	force_reload
	RETVAL=$?
	;;
     status)
	if [ $running -ne 0 ]; then
	    case "$running" in
		1) echo $"$prog dead but pid file exists" ;;
		2) echo $"$prog dead but subsys locked" ;;
		3) echo $"$prog is stopped" ;;
		4) echo $"$prog status is unknown" ;;
	    esac

	    exit $running
	fi

	# WARNING: status uses pidof and may find more pids than it
	# should.
	status -p $pidfile $prog
	RETVAL=$?
	;;
     *)
	echo $"Usage: $0 
{start|stop|restart|try-restart|reload|force-reload|status}"
	RETVAL=2
esac

exit $RETVAL




More information about the devel mailing list