[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: LSB-ish init script, RFC



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



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]