Novell Home

Creating Custom init Scripts

Novell Cool Solutions: Feature
By Kirk Coombs

Digg This - Slashdot This

Posted: 27 Jun 2005
 


background

Novell/SUSE Linux uses a system of scripts to determine which services to run on system boot. These scripts exist in /etc/init.d/ (or the symbolic link /etc/rc.d/), and are referred to as 'init scripts.' They help dictate which services are active in each runlevel, and also allow the services to be manually controlled. For more information on runlevels, see this article.

Each service that ships with Novell/SUSE Linux installs a script in /etc/init.d/. If a custom service is installed it may not have a init script. This article explains how to create these scripts.


how init scripts are used

init scripts are essentially just shell scripts with options for performing basic actions on a service. They can be invoked manually, or automatically by the system. To invoke an init script manually, the syntax is:

/etc/init.d/service parameter

For example, to start the Apache2 service, execute:

# /etc/init.d/apache2 start
Starting httpd2 (prefork)                                            done

There are several default parameters which can be used with an init script. They are explained in Table 1, which has been taken from the SUSE Linux Professional Administration Guide.

Table 1: The Standard init Script Parameters

start

Start service.

stop

Stop service.

restart

If the service is running, stop it then restart it. If it is not running, start it.

reload

Reload the configuration without stopping and restarting the service.

force-reload

Reload the configuration if the service supports this. Otherwise, do the same as if restart had been given.

status

Show the current status of service.

For a service to be included in a runlevel, it must be symbolically linked into the desired runlevel (found in /etc/rc.d/rc0.d/ through /etc/rc.d/rc6.d/). These links specify which services to start and stop as each runlevel is entered. The links are named in such a way that they control the order the scripts are started and stopped. First, the name starts with an S or K. An S indicates the script is to receive the 'start' parameter, and 'K' indicates it should receive the 'stop' parameter. Next, there is a two-digit number. This specifies the order a service should be started/stopped in. Lastly, the name of the service is listed.

For example, to start service /etc/init.d/foo in runlevel 5 the link may be /etc/init.d/rc5.d/S10foo -> /etc/init.d/foo. If foo is dependent on any other services, they should be numbered lower than 10. These links are automatically managed by the tool insserv and the YaST runlevel editor based on information contained in the init scripts.

In addition, a init script should also always have a symbolic link to /sbin/rc<servicename>. . For example, foo should have the link /sbin/rcfoo -> /etc/init.d/foo.


the anatomy of an init script

Novell/SUSE Linux ships with an example init script, located at /etc/rc.d/skeleton. It has several critical sections to edit, the most important of which are highlighted here. For more information see the /etc/init.d/skeleton file--it is very well commented.

This example will build an init script for the sample service bar, which has a binary located at /usr/bin/bar. It uses the configuration file /etc/bar.cfg, and is a network-dependent service. This script will only show the most basic functions of an init script. For more advanced information, check the /etc/init.d/skeleton file, or look through other scripts contained in /etc/init.d/.

  1. Define the interpreter. You need to specify which interpreter will be used to execute this script. The first line of an init script should aways be:

    #! /bin/sh

  2. Author and other useful information. It is always good to place contact information or anything else which may be useful at the beginning of a script.

    # Copyright (c) 2005 John Doe
    # All rights reserved.
    #
    # Author: John Doe, 2005
    #
    # /etc/init.d/bar
    #   and its symbolic link
    # /usr/sbin/rcbar

  3. Populate "INIT INFO" The entries in the "INIT INFO" section are comments which are read by insserv and the YaST runlevel editor. They specify what this service should be known as to other init scripts, what other services are required for this one to run, and what runlevels to be active in. The following entry specifies that other init scripts can refer to this service as $bar. It should be started after the network is brought up, and should be active in runlevels 3 and 5. It should be stopped in any other.

    ### BEGIN INIT INFO
    # Provides:          bar
    # Required-Start:    $network
    # Required-Stop:
    # Default-Start:     3 5
    # Default-Stop:      0 1 2 6
    # Short-Description: bar daemon, providing a useful network service
    # Description:       The bar daemon is a sample network
    #	service.  We want it to be active in runlevels 3
    #	and 5, as these are the runlevels with the network
    #	available.
    ### END INIT INFO

  4. Check for the binary and configuration files. Load the configuration variables. It is probably a good idea to have the script check for the binary. Configuration files, if any, should be checked, and the variables from them should be loaded into environment variables.

    # Check for missing binaries
    BAR_BIN=/usr/bin/bar
    test -x $BAR_BIN || { echo "$BAR_BIN not installed";
            if [ "$1" = "stop" ]; then exit 0;
            else exit 5; fi; }
    
    # Check for existence of needed config file and read it
    BAR_CONFIG=/etc/bar.cfg
    test -r $BAR_CONFIG || { echo "$BAR_CONFIG not existing";
            if [ "$1" = "stop" ]; then exit 0;
            else exit 6; fi; }
    
    # Read config
    . $BAR_CONFIG

  5. Load and reset the /etc/rc_status script for this service. This script is used to oversee and report the status of the given service.

    # Load the rc.status script for this service.
    . /etc/rc.status
    
    # Reset status of this service
    rc_reset

  6. Define the control parameters for the service. This is were the start, stop, and other control parameters for bar are defined. In general, the command /usr/bin/bar should be started and stopped using startproc and killproc respectively. The status of a process can be checked with checkproc.

    • startproc: startproc starts a process, specified by a full path to the executable. It can take many parameters such as the priority the process should be executed with, where to redirect STDIN and STDOUT (i.e. where the log file is), and which user to execute the process as. startproc also writes a file out to /var/run/<executablename>.pid which contains the process number assigned to the service. See the startproc (8) manpage for more information.

    • killproc: killproc kills a process which is given by a full path to the executable. By default, any process which is an instance of this executable is killed. killproc takes parameters such as which process to not kill if there is more than one running (given by specifying one of the .pid files created by startproc), and what signal to send the process (by default a SIGTERM is sent, then a SIGKILL if the process does not die within 5 seconds).
    • checkproc: checkproc works like killproc and startproc, returning the current status of a given process, which is specified by the full path to the executable from which the process was spawned.

    the command rc_status reads the return values of startproc, killproc, and checkproc and prints that status out to the user. For example, a green 'done' if the service started successfully, or a red 'failed' if it did not.

    Using startproc, killproc, checkproc, and rc_status, the rest of the section is very straightforward:

      case "$1" in
        start)
            echo -n "Starting bar "
            ## Start daemon with startproc(8). If this fails
            ## the return value is set appropriately by startproc.
            startproc $BAR_BIN
    
            # Remember status and be verbose
            rc_status -v
            ;;
        stop)
            echo -n "Shutting down bar "
            ## Stop daemon with killproc(8) and if this fails
            ## killproc sets the return value according to LSB.
    
            killproc -TERM $BAR_BIN
    
            # Remember status and be verbose
            rc_status -v
            ;;
        restart)
            ## Stop the service and regardless of whether it was
            ## running or not, start it again.
            $0 stop
            $0 start
    
            # Remember status and be quiet
            rc_status
            ;;
        reload)
            # If it supports signaling:
            echo -n "Reload service bar "
            killproc -HUP $BAR_BIN
            #touch /var/run/BAR.pid
            rc_status -v
    
            ## Otherwise if it does not support reload:
            #rc_failed 3
            #rc_status -v
            ;;
        status)
            echo -n "Checking for service bar "
            ## Check status with checkproc(8), if process is running
            ## checkproc will return with exit status 0.
    
            # Return value is slightly different for the status command:
            # 0 - service up and running
            # 1 - service dead, but /var/run/  pid  file exists
            # 2 - service dead, but /var/lock/ lock file exists
            # 3 - service not running (unused)
            # 4 - service status unknown :-(
            # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.)
    
            # NOTE: checkproc returns LSB compliant status values.
            checkproc $BAR_BIN
            # NOTE: rc_status knows that we called this init script with
            # "status" option and adapts its messages accordingly.
            rc_status -v
            ;;
        *)
            ## If no parameters are given, print which are avaiable.
            echo "Usage: $0 {start|stop|status|restart|reload}"
            exit 1
            ;;
    esac
  7. End the /etc/rc.status script.

    rc_exit
    Remember to make the new script executable. For example:
    chmod 744 /etc/init.d/bar
    Also, remember to make a symbolic link to /etc/init/bar in /sbin:
    ln -s /etc/init.d/bar /sbin/rcbar


enabling an init script

Novell/SUSE Linux provides several tools for managing init scripts. The most simple is innserv. For example, to have /etc/init.d/bar loaded with the default runlevels specified in the "INIT INFO" section, execute:

# innserv /etc/init.d/bar

To have it removed, type

# innserv -r /etc/init.d/bar

Another tool is the runlevel editor in YaST. It can be launched from the command-line with 'yast runlevel', or can be found under System. In simple mode, enabling a service places it in the default runlevels. In expert mode, the runlevels to be used can be customized.


Novell Cool Solutions (corporate web communities) are produced by WebWise Solutions. www.webwiseone.com

© 2014 Novell