Practical rc.d scripting in BSD
Prev |  | Next

# 3 A dummy script

The following script just emits a message each time the system boots up:

    #!/bin/sh

    . /etc/rc.subr

    name="dummy"
    start_cmd="${name}_start"
    stop_cmd=":"

    dummy_start()
    {
    	echo "Nothing started."
    }

    load_rc_config $name
    run_rc_command "$1"

Things to note are:

  An interpreted script should begin with the magic shebang line. That line specifies the interpreter program for the script. Due to the shebang line, the script can be invoked exactly like a binary program provided that it has the execute bit set. (See chmod(1).) For example, a system admin can run our script manually, from the command line:

      # /etc/rc.d/dummy start

  > Note: In order to be properly managed by the `rc.d` framework, its scripts need to be written in the sh(1) language. If you have a service or port that uses a binary control utility or a startup routine written in another language, install that element in `/usr/sbin` (for the system) or `/usr/local/sbin` (for ports) and call it from a sh(1) script in the appropriate `rc.d` directory.

  > Tip: If you would like to learn the details of why `rc.d` scripts must be written in the sh(1) language, see how `/etc/rc` invokes them by means of `run_rc_script`, then study the implementation of `run_rc_script` in `/etc/rc.subr`.

  In `/etc/rc.subr`, a number of sh(1) functions are defined for an `rc.d` script to use. The functions are documented in rc.subr(8). While it is theoretically possible to write an `rc.d` script without ever using rc.subr(8), its functions prove extremely handy and make the job an order of magnitude easier. So it is no surprise that everybody resorts to rc.subr(8) in `rc.d` scripts. We are not going to be an exception.

  An `rc.d` script must source `/etc/rc.subr` (include it using `.`) before it calls rc.subr(8) functions so that sh(1) has an opportunity to learn the functions. The preferred style is to source `/etc/rc.subr` first of all.

  > Note: Some useful functions related to networking are provided by another include file, `/etc/network.subr`.

  The mandatory variable `name` specifies the name of our script. It is required by rc.subr(8). That is, each `rc.d` script must set `name` before it calls rc.subr(8) functions.

  Now it is the right time to choose a unique name for our script once and for all. We will use it in a number of places while developing the script. For a start, let us give the same name to the script file, too.

  > Note: The current style of `rc.d` scripting is to enclose values assigned to variables in double quotes. Keep in mind that it is just a style issue that may not always be applicable. You can safely omit quotes from around simple words without sh(1) metacharacters in them, while in certain cases you will need single quotes to prevent any interpretation of the value by sh(1). A programmer should be able to tell the language syntax from style conventions and use both of them wisely.

  The main idea behind rc.subr(8) is that an `rc.d` script provides handlers, or methods, for rc.subr(8) to invoke. In particular, `start`, `stop`, and other arguments to an `rc.d` script are handled this way. A method is a sh(1) expression stored in a variable named ``argument`_cmd`, where `argument` corresponds to what can be specified on the script's command line. We will see later how rc.subr(8) provides default methods for the standard arguments.

  > Note: To make the code in `rc.d` more uniform, it is common to use `${name}` wherever appropriate. Thus a number of lines can be just copied from one script to another.

  We should keep in mind that rc.subr(8) provides default methods for the standard arguments. Consequently, we must override a standard method with a no-op sh(1) expression if we want it to do nothing.
  The body of a sophisticated method can be implemented as a function. It is a good idea to make the function name meaningful.

  > Important: It is strongly recommended to add the prefix `${name}` to the names of all functions defined in our script so they never clash with the functions from rc.subr(8) or another common include file.

  This call to rc.subr(8) loads rc.conf(5) variables. Our script makes no use of them yet, but it still is recommended to load rc.conf(5) because there can be rc.conf(5) variables controlling rc.subr(8) itself.
  Usually this is the last command in an `rc.d` script. It invokes the rc.subr(8) machinery to perform the requested action using the variables and methods our script has provided.

Prev | Home | Next
Outlining the task |  | A configurable dummy script