Source string Read only

(itstool) path: callout/screen
63/630
Context English State
The basic ideas behind BSD <filename>rc.d</filename> are <emphasis>fine modularity</emphasis> and <emphasis>code reuse</emphasis>. <emphasis>Fine modularity</emphasis> means that each basic <quote>service</quote> such as a system daemon or primitive startup task gets its own <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry> script able to start the service, stop it, reload it, check its status. A particular action is chosen by the command-line argument to the script. The <filename>/etc/rc</filename> script still drives system startup, but now it merely invokes the smaller scripts one by one with the <option>start</option> argument. It is easy to perform shutdown tasks as well by running the same set of scripts with the <option>stop</option> argument, which is done by <filename>/etc/rc.shutdown</filename>. Note how closely this follows the Unix way of having a set of small specialized tools, each fulfilling its task as well as possible. <emphasis>Code reuse</emphasis> means that common operations are implemented as <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry> functions and collected in <filename>/etc/rc.subr</filename>. Now a typical script can be just a few lines' worth of <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry> code. Finally, an important part of the <filename>rc.d</filename> framework is <citerefentry><refentrytitle>rcorder</refentrytitle><manvolnum>8</manvolnum></citerefentry>, which helps <filename>/etc/rc</filename> to run the small scripts orderly with respect to dependencies between them. It can help <filename>/etc/rc.shutdown</filename>, too, because the proper order for the shutdown sequence is opposite to that of startup.
The BSD <filename>rc.d</filename> design is described in <link linkend="lukem">the original article by Luke Mewburn</link>, and the <filename>rc.d</filename> components are documented in great detail in <link linkend="manpages">the respective manual pages</link>. However, it might not appear obvious to an <filename>rc.d</filename> newbie how to tie the numerous bits and pieces together in order to create a well-styled script for a particular task. Therefore this article will try a different approach to describe <filename>rc.d</filename>. It will show which features should be used in a number of typical cases, and why. Note that this is not a how-to document because our aim is not at giving ready-made recipes, but at showing a few easy entrances into the <filename>rc.d</filename> realm. Neither is this article a replacement for the relevant manual pages. Do not hesitate to refer to them for more formal and complete documentation while reading this article.
There are prerequisites to understanding this article. First of all, you should be familiar with the <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry> scripting language in order to master <filename>rc.d</filename>. In addition, you should know how the system performs userland startup and shutdown tasks, which is described in <citerefentry><refentrytitle>rc</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
This article focuses on the FreeBSD branch of <filename>rc.d</filename>. Nevertheless, it may be useful to NetBSD developers, too, because the two branches of BSD <filename>rc.d</filename> not only share the same design but also stay similar in their aspects visible to script authors.
Outlining the task
A little consideration before starting <envar>$EDITOR</envar> will not hurt. In order to write a well-tempered <filename>rc.d</filename> script for a system service, we should be able to answer the following questions first:
Is the service mandatory or optional?
Will the script serve a single program, e.g., a daemon, or perform more complex actions?
Which other services will our service depend on, and vice versa?
From the examples that follow we will see why it is important to know the answers to these questions.
A dummy script
The following script just emits a message each time the system boots up:
#!/bin/sh<co xml:id="rcng-dummy-shebang"/>

. /etc/rc.subr<co xml:id="rcng-dummy-include"/>

name="dummy"<co xml:id="rcng-dummy-name"/>
start_cmd="${name}_start"<co xml:id="rcng-dummy-startcmd"/>
stop_cmd=":"<co xml:id="rcng-dummy-stopcmd"/>

dummy_start()<co xml:id="rcng-dummy-startfn"/>
{
echo "Nothing started."
}

load_rc_config $name<co xml:id="rcng-dummy-loadconfig"/>
run_rc_command "$1"<co xml:id="rcng-dummy-runcommand"/>
Things to note are:
An interpreted script should begin with the magic <quote>shebang</quote> 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 <citerefentry><refentrytitle>chmod</refentrytitle><manvolnum>1</manvolnum></citerefentry>.) For example, a system admin can run our script manually, from the command line:
<prompt>#</prompt> <userinput>/etc/rc.d/dummy start</userinput>
In order to be properly managed by the <filename>rc.d</filename> framework, its scripts need to be written in the <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry> 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 <filename>/usr/sbin</filename> (for the system) or <filename>/usr/local/sbin</filename> (for ports) and call it from a <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry> script in the appropriate <filename>rc.d</filename> directory.
If you would like to learn the details of why <filename>rc.d</filename> scripts must be written in the <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry> language, see how <filename>/etc/rc</filename> invokes them by means of <function>run_rc_script</function>, then study the implementation of <function>run_rc_script</function> in <filename>/etc/rc.subr</filename>.
In <filename>/etc/rc.subr</filename>, a number of <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry> functions are defined for an <filename>rc.d</filename> script to use. The functions are documented in <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry>. While it is theoretically possible to write an <filename>rc.d</filename> script without ever using <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry>, its functions prove extremely handy and make the job an order of magnitude easier. So it is no surprise that everybody resorts to <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry> in <filename>rc.d</filename> scripts. We are not going to be an exception.
An <filename>rc.d</filename> script must <quote>source</quote> <filename>/etc/rc.subr</filename> (include it using <quote><command>.</command></quote>) <emphasis>before</emphasis> it calls <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry> functions so that <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry> has an opportunity to learn the functions. The preferred style is to source <filename>/etc/rc.subr</filename> first of all.
Some useful functions related to networking are provided by another include file, <filename>/etc/network.subr</filename>.
<anchor xml:id="name-var"/>The mandatory variable <envar>name</envar> specifies the name of our script. It is required by <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry>. That is, each <filename>rc.d</filename> script <emphasis>must</emphasis> set <envar>name</envar> before it calls <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry> 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.
The current style of <filename>rc.d</filename> 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 <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry> metacharacters in them, while in certain cases you will need single quotes to prevent any interpretation of the value by <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry>. A programmer should be able to tell the language syntax from style conventions and use both of them wisely.
The main idea behind <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry> is that an <filename>rc.d</filename> script provides handlers, or methods, for <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry> to invoke. In particular, <option>start</option>, <option>stop</option>, and other arguments to an <filename>rc.d</filename> script are handled this way. A method is a <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry> expression stored in a variable named <envar><replaceable>argument</replaceable>_cmd</envar>, where <replaceable>argument</replaceable> corresponds to what can be specified on the script's command line. We will see later how <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry> provides default methods for the standard arguments.
To make the code in <filename>rc.d</filename> more uniform, it is common to use <envar>${name}</envar> wherever appropriate. Thus a number of lines can be just copied from one script to another.
We should keep in mind that <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry> provides default methods for the standard arguments. Consequently, we must override a standard method with a no-op <citerefentry><refentrytitle>sh</refentrytitle><manvolnum>1</manvolnum></citerefentry> 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.
It is strongly recommended to add the prefix <envar>${name}</envar> to the names of all functions defined in our script so they never clash with the functions from <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry> or another common include file.
This call to <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry> loads <citerefentry><refentrytitle>rc.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> variables. Our script makes no use of them yet, but it still is recommended to load <citerefentry><refentrytitle>rc.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> because there can be <citerefentry><refentrytitle>rc.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> variables controlling <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry> itself.
Usually this is the last command in an <filename>rc.d</filename> script. It invokes the <citerefentry><refentrytitle>rc.subr</refentrytitle><manvolnum>8</manvolnum></citerefentry> machinery to perform the requested action using the variables and methods our script has provided.

Loading…

No matching activity found.

Browse all component changes

Glossary

English English
No related strings found in the glossary.

Source information

Source string comment
(itstool) path: callout/screen
Flags
no-wrap, read-only
Source string location
article.translate.xml:232
String age
a year ago
Source string age
a year ago
Translation file
articles/rc-scripting.pot, string 31