Now let us add some controls to our dummy script. As you may know, rc.d scripts are controlled with rc.conf(5). Fortunately, rc.subr(8) hides all the complications from us. The following script uses rc.conf(5) via rc.subr(8) to see whether it is enabled in the first place, and to fetch a message to show at boot time. These two tasks in fact are independent. On the one hand, an rc.d script can just support enabling and disabling its service. On the other hand, a mandatory rc.d script can have configuration variables. We will do both things in the same script though:
#!/bin/sh . /etc/rc.subr name="dummy" rcvar=`set_rcvar` start_cmd="${name}_start" stop_cmd=":" load_rc_config $name eval "${rcvar}=\${${rcvar}:-'NO'}" dummy_msg=${dummy_msg:-"Nothing started."} dummy_start() { echo "$dummy_msg" } run_rc_command "$1"
What changed in this example?
-
The variable rcvar specifies the name of the ON/OFF knob variable. The reason to obtain the variable name from rc.subr(8) by calling set_rcvar is that different operating systems adopted different conventions for it. Namely, FreeBSD sticks to the ${name}_enable scheme while NetBSD uses just ${name} variables in its rc.conf(5) . For example, our script will be controlled by dummy_enable in FreeBSD and by dummy in NetBSD.
- Now load_rc_config is invoked earlier in the script, before any rc.conf(5) variables are accessed.
-
Note: While examining rc.d scripts, keep in mind that sh(1) defers the evaluation of expressions in a function until the latter is called. Therefore it is not an error to invoke load_rc_config as late as just before run_rc_command and still access rc.conf(5) variables from the method functions exported to run_rc_command. This is because the method functions are to be called by run_rc_command, which is invoked after load_rc_config.
-
A warning will be emitted by run_rc_command if rcvar itself is set, but the indicated knob variable is unset. If your rc.d script is for the base system, you should add a default setting for the knob to /etc/defaults/rc.conf and document it in rc.conf(5) . Otherwise it is your script that should provide a default setting for the knob. A portable approach to the latter case is shown in the example.
-
Note: You can make rc.subr(8) act as though the knob is set to ON, irrespective of its current setting, by prefixing the argument to the script with one or force, as in onestart or forcestop. Keep in mind though that force has other dangerous effects we will touch upon below, while one just overrides the ON/OFF knob. E.g., assume that dummy_enable is OFF. The following command will run the start method in spite of the setting:
# /etc/rc.d/dummy onestart
-
Now the message to be shown at boot time is no longer hard-coded in the script. It is specified by an rc.conf(5) variable named dummy_msg. This is a trivial example of how rc.conf(5) variables can control an rc.d script.
-
Important: The names of all rc.conf(5) variables used exclusively by our script must have the same prefix: ${name}. For example: dummy_mode, dummy_state_file, and so on.
Note: While it is possible to use a shorter name internally, e.g., just msg, adding the unique prefix ${name} to all global names introduced by our script will save us from possible collisions with the rc.subr(8) namespace.
As long as an rc.conf(5) variable and its internal equivalent are the same, we can use a more compact expression to set the default value:
: ${dummy_msg:="Nothing started."}
The current style is to use the more verbose form though.
As a rule, rc.d scripts of the base system need not provide defaults for their rc.conf(5) variables because the defaults should be set in /etc/defaults/rc.conf instead. On the other hand, rc.d scripts for ports should provide the defaults as shown in the example.
- Here we use dummy_msg to actually control our script, i.e., to emit a variable message.