Novell Home

Writing Init Scripts

From Developer Community

Contents

About Linux Initialization Scripts (Init Scripts)

If you have an application that needs to be started or stopped in a specific way, one that needs to run without a controlling terminal, and especially one that needs to start when the system starts and shut itself down when the system shuts itself down, you need to learn about init scripts. Daemons are a particular type of application that usually can benefit from an init script, but there are other uses for init scripts as well.

In this article we'll learn how to write an init script for a simple application that I use at home called DVArchive. DVArchive is an application that runs on a PC which allows a PC to interface with a DVR like ReplayTV, to store and stream programs. DVArchive usually runs as a rich client application, but on Linux you can also run it in "headless" mode. With an init script for DVArchive, I can turn my home server into a media storage and streaming device. Sweet!


Init Scripts are Bash Scripts

To start out, we need to understand that most init scripts are bash scripts. In fact, pretty much all of the scripts I have seen are bash scripts. Technically, however, they are just programs that invoke other programs in a certain way and conform to certain conventions. I assume they can be written in another scripting language, like Perl, or even in another programming language like C++ if you desire.

However, since most init scripts are bash scripts, your best examples will be in bash. And SUSE Linux comes with a lot of built in commands and facilities to make it easy to create init scripts in bash. That's probably the way you will want to go.


Because most init scripts are written in bash script, they are all available to you in source code form. In fact, SUSE Linux comes with a skeleton script at the location /etc/init.d/skeleton that is thoroughly documented and can be copied to use as a starting point for your init script. And of course you can reference the other scripts for help if you need to.


For instructive purposes, I'll start from scratch. To start, we'll create a script called "dvarchive", which gets created in the /etc/init.d directory with permissions 744.

The first line of the script looks like this:

#!/bin/sh

or

#!/bin/bash

It really doesn't matter since on SUSE Linux /bin/sh is just a symbolic link that points to /bin/bash anyway.


Important Pre-Processing Steps

Sourcing /etc/rc.status

The next line you will want to include is the following:

test -s /etc/rc.status && . /etc/rc.status && rc_reset

What does this line do?

  • Tests to make sure there is a file called /etc/rc.status and that /etc/rc.status has a size greater than zero
  • Sources /etc/rc.status (essentially includes the file inline). /etc/rc.status does the following:
    • Sets up environment variables
    • Checks the path
    • Defines variables and functions based upon the type of terminal being used
    • It may do other things in the future - just include it and you'll be fine
  • Calls rc_reset, which resets variables used within the script to control execution


Init Information

At the head of your script you can provide an "INIT INFO" section, which is essentially a description in a standardized format of what your service is about. This is used by the YaST runlevel editor.

# Provides:          dvarchive
# Required-Start:    network
# Required-Stop:
# Default-Start:     3 5
# Default-Stop:      0 1 2 6
# Short-Description: Starts the dvarchive daemon
# Description:       Starts the dvarchive daemon, attached to a virtual
#                    frame buffer.


Setting Up Variables

Many init scripts at this point will perform a few other more customized initialization steps, such as defining variables for paths and values to be used later, finding, reading, and validating configuration information and files, verifying the existence and executability of the application that pertains to this init script, etc.


In my case, I'm going to set up a few variables for convenience sake.

XVFB_PATH=/usr/X11R6/bin
XVFB_APP=Xvfb
XVFB=${XVFB_PATH}/${XVFB_APP}
DSP=7
XFONTS=/usr/X11R6/lib/X11/fonts/misc
XVFB_CMD="${XVFB} :${DSP} -ac -fp ${XFONTS}"
JAVA=/usr/bin/java
DVARCHIVE_PATH=/opt/dvarchive
DVARCHIVE_APP=DVArchive
DVARCHIVE_JAR=${DVARCHIVE_APP}.jar
DVARCHIVE_CMD="${JAVA} -jar ${DVARCHIVE_PATH}/${DVARCHIVE_JAR} --daemon"
DVARCHIVE_PIDFILE=/var/run/dvarchive.pid
DVARCHIVE_XVFB_PIDFILE=/var/run/dvarchive_xvfb.pid
DVARCHIVE_LOG=/var/log/dvarchive

One quirk with DVArchive is that, in order to run it without a terminal, you need to set up Xvfb - the X virtual frame buffer. This acts like a terminal for the application to display to without actually requiring a terminal. To run DVArchive we'll need to start Xvfb along with the DVArchive app itself.

Everything else should be pretty much self-evident.


Performing Pre-Processing Checks

Before we get any farther, we can do a few checks to see whether we can have success. I wrote a function called test_for_app that can test for the existence of a specific executable or file, and then display an error message if it isn't found. Then I use this to check for Xvfb, java, and DVArchive. For example:

test_for_app ()
{
    app_found=0
    if [ "f" = "$2" ] && [ -f $1 ]; then
        app_found=1
    elif [ "x" = "$2" ] && [ -x $1 ]; then
        app_found=1
    fi
    if [ 0 = $app_found ]; then
        echo -n "Warning:  Couldn't find $1"
        if [ "$1" = "stop" ] || [ "$1" = "xvfb_stop" ]; then
            rc_failed 0
        else
            rc_failed 5
        fi
        rc_status -v
        rc_exit
    fi
}

test_for_app ${XVFB} x
test_for_app ${JAVA} x
test_for_app ${DVARCHIVE_PATH}/${DVARCHIVE_JAR} f

Here we are just checking to see if the Xvfb application, the java applicatoin, and the DVArchive application are installed. If they are not installed we can abort. Other checks are also possible here - for example, if there is a configuration file, we could check for that.

Notice the sequence of steps if the tests fail. We first print out a somewhat descriptive error message. rc_failed 5 sets the status to a failed state with a return code of 5. rc_status -v prints out the currently reported state. rc_exit causes the script to exit with the return code.

We'll use this sequence frequently.


Here's an example of the output displayed if the DVArchive app isn't found:

Couldn't find /opt/dvarchive/DVArchive.jar                               failed

In addition, on my computer the word "failed" is displayed in red. This allows my error messages to give the same appearance as other startup applications when it succeeds or fails.


Taking Action

Now we get into the meat of the script. Usually the script will be invokved with a single argument, which tells the script what we want to do - start, stop, etc. You can put what you want in here, but some basics that you'll want to consider are the following:

  • start - Starts up the application if it isn't already running
  • stop - Gracefully shuts the application down if it is running
  • status - Reports whether the application is running or not

Many applications include other options, like restart. restart in some cases is just stop followed by start, but in other cases, the script might just send a signal (like SIGHUP) to the application telling it to reload the configuration. Alternatively, you may wish to implement restart as stop followed by start, and implement a reload option in addition that will send SIGHUP.


Script Usage

Regardless of what options you provide, you should make it easy for your users to learn how to invoke the script. This is best done with a usage or help option, or by default if no other option is selected. Let's do that first.


First, my usage function:

usage ()
{
        echo ""
        echo "Usage: $0 <command>"
        echo ""
        echo "where <command> is one of the following:"
        echo "    start - start DVArchive if it is not running"
        echo "    stop - stop DVArchive if it is running"
        echo "    status - report whether DVArchive is running"
        echo "    restart - stop and restart DVArchive"
        echo "    usage, help - print this message"
}


Option processing is usually implemented as a simple case statement. The first cases I'll handle are usage, help, and * - the default case.

case "$1" in
        usage|help)
                usage
                rc_exit
                ;;
        *)
                usage
                rc_failed 1
                rc_status -v
                rc_exit
esac

If I run /etc/init.d/dvarchive usage (or help), I will see the usage information printed out:

Usage: /etc/init.d/dvarchive <command>

where <command> is one of the following:
    start - start DVArchive if not running
    stop - stop DVArchive if running
    status - report whether DVArchive is running
    restart - stop and restart DVArchive
    usage, help - print this message

I can assume that if the user specifies the usage or help option, they wanted the usage message. If another option is provided that I don't know about, or no option is provided, I don't know what the user wanted. So I mark this as a failed execution - we exit with a failure status and show the failure message. Everything else is the same.

Usage: /etc/init.d/dvarchive <command>

where <command> is one of the following:
    start - start DVArchive if not running
    stop - stop DVArchive if running
    status - report whether DVArchive is running
    restart - stop and restart DVArchive
    usage, help - print this message
                                                                      failed


A Slight Diversion - The "*proc" Commands

As we said earlier, the primary purposes of this script are to start, stop, and get the status of an application. There are three applications provided on SUSE Linux to faciliate this:

  • startproc - Takes the full path of an application, and starts that application if there is no running instance of that application found
  • killproc - Takes the full path of an application, and tries to terminate all running processes for that path
  • checkproc - Takes the full path of an application, and checks for running processes for that path

You'll definitely want to check the man pages for details on these commands. We'll be using them in our script.


Starting the Application

Next lets implement the start option. Starting the application uses the following logic sequence:

  • Check to see if the application is already running. checkproc will do this for us. There are a few possible outcomes:
    • The application is not running - which is what we would expect.
    • The application is running - in which case we can do nothing, or shut it down and start over, or whatever else we think is necessary for our situation.
    • The application is not running but a PID file exists, which indicates an improper shutdown, or a crash, or something similar. We should notify the user in this case.
    • Our attempt to check the application failed, which is a problem that should be reported.
  • Barring any errors, we would at this point try to start the application, using startproc if possible.

This is a bit more complicated in our scenario, since we have to also start a virtual frame buffer session for our application. Here's how I did it:

case "$1" in
    start|xvfb_start)
        checkproc -p ${DVARCHIVE_XVFB_PIDFILE} ${XVFB}
        case $? in
            0)
                echo "${XVFB_APP} already running"
                ;;
            1)
                echo "Found stale pidfile for ${XVFB_APP} - unclean shutdown?"
                rm ${DVARCHIVE_XVFB_PIDFILE}
                ;;
            3)
                # not running - ok
                ;;
            *)
                echo "Check for ${XVFB_APP} failed"
                rc_failed
                rc_status -v1
                rc_exit
        esac
        export DISPLAY=":${DSP}.0"
        echo -n "Starting ${XVFB_APP} for ${DVARCHIVE_APP} "
        startproc -f -p ${DVARCHIVE_XVFB_PIDFILE} ${XVFB_CMD} >> ${DVARCHIVE_LOG} 2>&1
        if ! [ 0 = $? ]; then
            echo -n "(Error - "
            case $? in
                2)
                    echo -n "invalid arguments"
                    ;;
                4)
                    echo -n "insufficient permission"
                    ;;
                5)
                    echo -n "no such program"
                    ;;
                7)
                    echo -n "launch failure"
                    ;;
                *)
                    echo -n "unspecified error"
                    ;;
            esac
            echo -n ")"
            rc_failed
            rc_status -v1
            rc_exit
        fi
        get_pid_for_cmd `eval echo ${XVFB_CMD} | sed -e 's/ //g'`
        if [ 0 = $pid ]; then
            echo "Warning - Couldn't obtain PID for ${XVFB_APP} "
        else
            echo $pid > ${DVARCHIVE_XVFB_PIDFILE}
        fi
        rc_status -v
        # Xvfb started
        if [ $1 = "start" ]; then
            checkproc -p ${DVARCHIVE_PIDFILE} ${JAVA}
            case $? in
                0)
                    echo "${DVARCHIVE_APP} already running"
                    ;;
                1)
                    echo "Found stale pidfile for ${DVARCHIVE_APP} - unclean shutdown?"
                    rm ${DVARCHIVE_PIDFILE}
                    ;;
                3)
                    # not running - ok
                    ;;
                *)
                    echo "Check for ${DVARCHIVE_APP} failed"
                    rc_failed
                    rc_status -v1
                    rc_exit
            esac
            echo -n "Starting ${DVARCHIVE_APP}"
            echo Y | ${DVARCHIVE_CMD} >> ${DVARCHIVE_LOG} 2>&1 &
            if ! [ 0 = $? ]; then
                echo "Failed to start ${DVARCHIVE_APP}"
                rc_failed
                rc_status -v1
                rc_exit
            fi
            get_pid_for_cmd `eval echo ${DVARCHIVE_CMD} | sed -e 's/ //g'`
            if [ 0 = $pid ]; then
                echo "Warning - Couldn't obtain PID for ${DVARCHIVE_APP} "
            else
                echo $pid > ${DVARCHIVE_PIDFILE}
            fi
            rc_status -v
        fi
        ;;

This is pretty lengthy, but really not that hard to understand. The first thing we are going to do is check to see whether the Xvfb application is running, and based on the return value from checkproc, take appropriate steps.

If there were no errors, we continue on to run the application itself. We need to export a value for the DISPLAY variable which will be the same as the display we assign to Xvfb. We use startproc to start Xvfb, and if there are any errors in trying to start it, we report those errors to the user.

Once the process has started, we need to obtain the process ID to write it to the pid file. A function I wrote, called get_pid_for_cmd, does this for us (we'll talk about this function later).


After we are done starting Xvfb, we check to see if the user wanted to start Xvfb only, or if they wanted to start everything. Usually we will start everything; this capability was added primarily to ease debugging. Essentially the same sequence of steps is followed to start DVArchive.

There is one exception - I didn't use startproc to start DVArchive. When you run DVArchive with the --daemon option, it displays a text dialog of the EULA that I've read and agreed to many times, but you have to manually agree to it each time. Unfortunately, DVArchive doesn't remember that I accepted the EULA, nor does it give me an option to bypass the agreement. In order to make this work, I echo Y and pipe that into the command. This isn't as good as what startproc does for me but it will have to do.


If you looked, you may have noticed that the command that I pass into checkproc isn't the same as the one executed (either directly or via startproc). checkproc only looks for the full path to the command run, without arguments. This is why it is important that we specify the pid file to checkproc, especially when checking for the DVArchive process. The command is /usr/bin/java; it is not unlikely that there could be other running processes with the same command path. Specifying the pid file tells it to only consider any applications that are associated with that pid file.


Stopping the Application

Whew, that was a bit of work. Fortunately, starting the process is usually the part that requires the most work. Our next step is to be able to stop the process if it is running.

Stopping a process is fairly straightforward. The basic line of logic is the following:

  • Check for the process using checkproc.
  • Terminate the process using killproc.

Here's the code:

    stop|xvfb_stop)
        if [ $1 = "stop" ]; then
            checkproc -p ${DVARCHIVE_PIDFILE} ${JAVA} || echo -n "(Warning: not running)"
            killproc -p ${DVARCHIVE_PIDFILE} -t 10 ${JAVA}
            rc_status -v
        fi
        echo -n "Shutting down ${XVFB_APP} "
        checkproc -p ${DVARCHIVE_XVFB_PIDFILE} ${XVFB} || echo -n "(Warning: not running)"
        killproc -p ${DVARCHIVE_XVFB_PIDFILE} -t 10 ${XVFB}
        rc_status -v
        ;;

This is pretty straightforward. First, we stop DVArchive, then we stop Xvfb. Checking for '"1 = "stop"' allows us to stop only Xvfb if we want (again, primarily useful for debugging).

By the way, killproc isn't quite as brutal as it sounds. It first sends a SIGTERM to the process, waits for it to die, then after a few seconds it will send a SIGKILL if necessary. By specifying the pid file to killproc, we make sure we only terminate the process that is associated with the pid file. This should be the one we started earlier.


Implementing Restart

Now that I can stop and start, implementing restart is a piece of cake:

    restart)
        $0 stop &>/dev/null
        $0 start &>/dev/null
        rc_status -v
        ;;

I simply invoke the same script to stop and start in succession. This works for my case. Some applications can be more gracefully restarted; in some cases, what is really required is to re-initialize the process. Whatever works for you.


Getting Application Status

The last thing to do is to allow the user to query the status of the applicaitons. This is pretty easy to do, since all we have to do is run checkproc and report the results of this command.

    status|xvfb_status)
        app_chk ${XVFB_APP} ${DVARCHIVE_XVFB_PIDFILE} ${XVFB}
        # Xvfb is running
        if [ $1 = "status" ]; then
            app_chk ${DVARCHIVE_APP} ${DVARCHIVE_PIDFILE} ${JAVA}
        fi
        ;;

I implemented the bulk of the logic for this in another function. I guess it is time to take a look at those functions now.


Helper Functions

I wrote two helper functions, get_pid_for_cmd and app_chk. Here's get_pid_for_cmd:

get_pid_for_cmd ()
{
    for pid in `ls -t /proc`; do
        if [ -d /proc/$pid ] && [ -f /proc/$pid/cmdline ]; then
            if [ "$1" = "$(</proc/$pid/cmdline)" ]; then
                return
            fi
        fi
    done
    pid=0
}

This function simply looks through /proc to find a process that matches the supplied command. By listing the entries in /proc with the -t option, we get them sorted by order of last modification, most recent first, which should make this search pretty fast. If the entry in /proc is a directory (not all are, but all the entries with the name of a process id are) and if the entry has a file named cmdline (which ours should have), then we simply compare the contents of cmdline to the command that is passed into our function as $1. If there is a match, we return and $pid is equal to the process id of the matching process. If no match is found, $pid is 0, which indicates an error.

If this is unfamiliar to you, take a look at the /proc filesystem and familiarize yourself with how it works. It is pretty cool.


Here's app_chk:

app_chk ()
{
    app=$1
    pidfile=$2
    cmd=$3
    echo -n "Checking for $app: "
    checkproc -p $pidfile $cmd
    case $? in
        0)
            echo -n "(running)"
            rc_failed 0
            ;;
        1)
            echo "(not running)"
            echo -n "Warning - PID file found"
            rc_failed 3
            ;;
        3)
            echo -n "(not running)"
            rc_failed 1
            ;;
        *)
            echo "(unknown)"
            echo "Warning - Couldn't get status"
            rc_failed 1
            rc_status -v1
            rc_exit
    esac
    rc_status -v
}

This function is mostly just a time-saver. It prints a "Checking for" message, then runs checkproc. An appropriate status message is printed based upon the return value from checkproc.


The Finished Product

Here's what we ended up with, top to bottom:

#!/bin/sh

# Provides:          dvarchive
# Required-Start:    network
# Required-Stop:
# Default-Start:     3 5
# Default-Stop:      0 1 2 6
# Short-Description: Starts the dvarchive daemon
# Description:       Starts the dvarchive daemon, attached to a virtual
#                    frame buffer.

XVFB_PATH=/usr/X11R6/bin
XVFB_APP=Xvfb
XVFB=${XVFB_PATH}/${XVFB_APP}
DSP=7
XFONTS=/usr/X11R6/lib/X11/fonts/misc
XVFB_CMD="${XVFB} :${DSP} -ac -fp ${XFONTS}"
JAVA=/usr/bin/java
DVARCHIVE_PATH=/opt/dvarchive
DVARCHIVE_APP=DVArchive
DVARCHIVE_JAR=${DVARCHIVE_APP}.jar
DVARCHIVE_CMD="${JAVA} -jar ${DVARCHIVE_PATH}/${DVARCHIVE_JAR} --daemon"
DVARCHIVE_PIDFILE=/var/run/dvarchive.pid
DVARCHIVE_XVFB_PIDFILE=/var/run/dvarchive_xvfb.pid
DVARCHIVE_LOG=/var/log/dvarchive

test -s /etc/rc.status && . /etc/rc.status && rc_reset

usage ()
{
    echo ""
    echo "Usage: $0 <command> "
    echo ""
    echo "where <command> is one of the following:"
    echo "    start - start $DVARCHIVE_APP if not running"
    echo "    stop - stop $DVARCHIVE_APP if running"
    echo "    status - report whether $DVARCHIVE_APP is running"
    echo "    restart - stop and restart $DVARCHIVE_APP"
    echo "    usage, help - print this message"
}

get_pid_for_cmd ()
{
    for pid in `ls -t /proc`; do
        if [ -d /proc/$pid ] && [ -f /proc/$pid/cmdline ]; then
            if [ "$1" = "$(</proc/$pid/cmdline)" ]; then
                return
            fi
        fi
    done
    pid=0
}

app_chk ()
{
    app=$1
    pidfile=$2
    cmd=$3
    echo -n "Checking for $app: "
    checkproc -p $pidfile $cmd
    case $? in
        0)
            echo -n "(running)"
            rc_failed 0
            ;;
        1)
            echo "(not running)"
            echo -n "Warning - PID file found"
            rc_failed 3
            ;;
        3)
            echo -n "(not running)"
            rc_failed 1
            ;;
        *)
            echo "(unknown)"
            echo "Warning - Couldn't get status"
            rc_failed 1
            rc_status -v1
            rc_exit
    esac
    rc_status -v
}

test_for_app ()
{
    app_found=0
    if [ "f" = "$2" ] && [ -f $1 ]; then
        app_found=1
    elif [ "x" = "$2" ] && [ -x $1 ]; then
        app_found=1
    fi
    if [ 0 = $app_found ]; then
        echo -n "Warning:  Couldn't find $1"
        if [ "$1" = "stop" ] || [ "$1" = "xvfb_stop" ]; then
            rc_failed 0
        else
            rc_failed 5
        fi
        rc_status -v
        rc_exit
    fi
}

test_for_app ${XVFB} x
test_for_app ${JAVA} x
test_for_app ${DVARCHIVE_PATH}/${DVARCHIVE_JAR} f

case "$1" in
    start|xvfb_start)
        checkproc -p ${DVARCHIVE_XVFB_PIDFILE} ${XVFB}
        case $? in
            0)
                echo "${XVFB_APP} already running"
                ;;
            1)
                echo "Found stale pidfile for ${XVFB_APP} - unclean shutdown?"
                rm ${DVARCHIVE_XVFB_PIDFILE}
                ;;
            3)
                # not running - ok
                ;;
            *)
                echo "Check for ${XVFB_APP} failed"
                rc_failed
                rc_status -v1
                rc_exit
        esac
        export DISPLAY=":${DSP}.0"
        echo -n "Starting ${XVFB_APP} for ${DVARCHIVE_APP} "
        startproc -f -p ${DVARCHIVE_XVFB_PIDFILE} ${XVFB_CMD} >> ${DVARCHIVE_LOG} 2>&1
        if ! [ 0 = $? ]; then
            echo -n "(Error - "
            case $? in
                2)
                    echo -n "invalid arguments"
                    ;;
                4)
                    echo -n "insufficient permission"
                    ;;
                5)
                    echo -n "no such program"
                    ;;
                7)
                    echo -n "launch failure"
                    ;;
                *)
                    echo -n "unspecified error"
                    ;;
            esac
            echo -n ")"
            rc_failed
            rc_status -v1
            rc_exit
        fi
        get_pid_for_cmd `eval echo ${XVFB_CMD} | sed -e 's/ //g'`
        if [ 0 = $pid ]; then
            echo "Warning - Couldn't obtain PID for ${XVFB_APP} "
        else
            echo $pid > ${DVARCHIVE_XVFB_PIDFILE}
        fi
        rc_status -v
        # Xvfb started
        if [ $1 = "start" ]; then
            checkproc -p ${DVARCHIVE_PIDFILE} ${JAVA}
            case $? in
                0)
                    echo "${DVARCHIVE_APP} already running"
                    ;;
                1)
                    echo "Found stale pidfile for ${DVARCHIVE_APP} - unclean shutdown?"
                    rm ${DVARCHIVE_PIDFILE}
                    ;;
                3)
                    # not running - ok
                    ;;
                *)
                    echo "Check for ${DVARCHIVE_APP} failed"
                    rc_failed
                    rc_status -v1
                    rc_exit
            esac
            echo -n "Starting ${DVARCHIVE_APP}"
            echo Y | ${DVARCHIVE_CMD} >> ${DVARCHIVE_LOG} 2>&1 &
            if ! [ 0 = $? ]; then
                echo "Failed to start ${DVARCHIVE_APP}"
                rc_failed
                rc_status -v1
                rc_exit
            fi
            get_pid_for_cmd `eval echo ${DVARCHIVE_CMD} | sed -e 's/ //g'`
            if [ 0 = $pid ]; then
                echo "Warning - Couldn't obtain PID for ${DVARCHIVE_APP} "
            else
                echo $pid > ${DVARCHIVE_PIDFILE}
            fi
            rc_status -v
        fi
        ;;
    stop|xvfb_stop)
        if [ $1 = "stop" ]; then
            checkproc -p ${DVARCHIVE_PIDFILE} ${JAVA} || echo -n "(Warning: not running)"
            killproc -p ${DVARCHIVE_PIDFILE} -t 10 ${JAVA}
            rc_status -v
        fi
        echo -n "Shutting down ${XVFB_APP} "
        checkproc -p ${DVARCHIVE_XVFB_PIDFILE} ${XVFB} || echo -n "(Warning: not running)"
        killproc -p ${DVARCHIVE_XVFB_PIDFILE} -t 10 ${XVFB}
        rc_status -v
        ;;
    status|xvfb_status)
        app_chk ${XVFB_APP} ${DVARCHIVE_XVFB_PIDFILE} ${XVFB}
        # Xvfb is running
        if [ $1 = "status" ]; then
            app_chk ${DVARCHIVE_APP} ${DVARCHIVE_PIDFILE} ${JAVA}
        fi
        ;;
    restart)
        $0 stop &>/dev/null
        $0 start &>/dev/null
        rc_status -v
        ;;
    usage|help)
        usage
        rc_exit
        ;;
    *)
        usage
        rc_failed 1
        rc_status -v
        rc_exit
esac

Although this script is specific to my purpose, it is pretty similar to other init scripts for other purposes.

To summarize: If you need to write an init script:

  • Start with /etc/init.d/skeleton as your baseline
  • Refer to other scripts in /etc/init.d for help and guidance
  • Take care of the primary actions - start, stop, status
  • Use /etc/rc.status, the rc_* functions, startproc, checkproc, and killproc where possible

Good luck!


See Also:

Creating Custom init Scripts (Novell Cool Solutions)

Multiprocess Linux Applications

Writing Linux Applications for Xinetd

Novell® Making IT Work As One

© 2009 Novell, Inc. All Rights Reserved.