LSB-ish init script, RFC

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


I went a little overboard on the || && shortcutting. "[ X ] || ( Y &&
exit )" will do Y and not exit, should be "if [ ! X ]; then Y ; exit ; fi"

Best,


matt

Matthew Farrellee wrote:
> 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 fedora-devel-list mailing list