stronger, as suggested by dougb@, but do so in the right context. I.e., don't fire all the requirements at once in the last section, but tell each of them where the current topic is most appropriate. Polish some wording and markup.
1193 lines
48 KiB
Text
1193 lines
48 KiB
Text
<!DOCTYPE article PUBLIC "-//FreeBSD//DTD DocBook V4.1-Based Extension//EN" [
|
|
<!ENTITY % articles.ent PUBLIC "-//FreeBSD//ENTITIES DocBook FreeBSD Articles Entity Set//EN">
|
|
%articles.ent;
|
|
]>
|
|
|
|
<article>
|
|
<articleinfo>
|
|
<title>Practical rc.d scripting in BSD</title>
|
|
|
|
<author>
|
|
<firstname>Yar</firstname>
|
|
|
|
<surname>Tikhiy</surname>
|
|
|
|
<affiliation>
|
|
<address><email>yar@FreeBSD.org</email></address>
|
|
</affiliation>
|
|
</author>
|
|
|
|
<copyright>
|
|
<year>2005</year>
|
|
|
|
<year>2006</year>
|
|
|
|
<holder>The FreeBSD Project</holder>
|
|
</copyright>
|
|
|
|
<pubdate>$FreeBSD$</pubdate>
|
|
|
|
<legalnotice id="trademarks" role="trademarks">
|
|
&tm-attrib.freebsd;
|
|
&tm-attrib.netbsd;
|
|
&tm-attrib.general;
|
|
</legalnotice>
|
|
|
|
<abstract>
|
|
<para>Beginners may find it difficult to relate the
|
|
facts from the formal documentation on the BSD
|
|
<filename>rc.d</filename> framework with the practical tasks
|
|
of <filename>rc.d</filename> scripting. In this article,
|
|
we consider a few typical cases of increasing complexity,
|
|
show <filename>rc.d</filename> features suited for each
|
|
case, and discuss how they work. Such an examination should
|
|
provide reference points for further study of the design
|
|
and efficient application of <filename>rc.d</filename>.</para>
|
|
</abstract>
|
|
</articleinfo>
|
|
|
|
<sect1 id="rcng-intro">
|
|
<title>Introduction</title>
|
|
|
|
<para>The historical BSD had a monolithic startup script,
|
|
<filename>/etc/rc</filename>. It was invoked by
|
|
&man.init.8; at system boot time and performed all userland
|
|
tasks required for multi-user operation: checking and
|
|
mounting file systems, setting up the network, starting
|
|
daemons, and so on. The precise list of tasks was not the
|
|
same in every system; admins needed to customize it. With
|
|
few exceptions, <filename>/etc/rc</filename> had to be modified,
|
|
and true hackers liked it.</para>
|
|
|
|
<para>The real problem with the monolithic approach was that
|
|
it provided no control over the individual components started
|
|
from <filename>/etc/rc</filename>. For instance,
|
|
<filename>/etc/rc</filename> could not restart a single daemon.
|
|
The system admin had to find the daemon process by hand, kill it,
|
|
wait until it actually exited, then browse through
|
|
<filename>/etc/rc</filename> for the flags, and finally type
|
|
the full command line to start the daemon again. The task
|
|
would become even more difficult and prone to errors if the
|
|
service to restart consisted of more than one daemon or
|
|
demanded additional actions. In a few words, the single
|
|
script failed to fulfill what scripts are for: to make the
|
|
system admin's life easier.</para>
|
|
|
|
<para>Later there was an attempt to split out some parts of
|
|
<filename>/etc/rc</filename> for the sake of starting the
|
|
most important subsystems separately. The notorious example
|
|
was <filename>/etc/netstart</filename> to bring up networking.
|
|
It did allow for accessing the network from single-user
|
|
mode, but it did not integrate well into the automatic startup
|
|
process because parts of its code needed to interleave with
|
|
actions essentially unrelated to networking. That was why
|
|
<filename>/etc/netstart</filename> mutated into
|
|
<filename>/etc/rc.network</filename>. The latter was no
|
|
longer an ordinary script; it comprised of large, tangled
|
|
&man.sh.1; functions called from <filename>/etc/rc</filename>
|
|
at different stages of system startup. However, as the startup
|
|
tasks grew diverse and sophisticated, the
|
|
<quote>quasi-modular</quote> approach became even more of a
|
|
drag than the monolithic <filename>/etc/rc</filename> had
|
|
been.</para>
|
|
|
|
<para>Without a clean and well-designed framework, the startup
|
|
scripts had to bend over backwards to satisfy the needs of
|
|
rapidly developing BSD-based operating systems. It became
|
|
obvious at last that more steps are necessary on the way to
|
|
a fine-grained and extensible <filename>rc</filename> system.
|
|
Thus BSD <filename>rc.d</filename> was born. Its acknowledged
|
|
fathers were Luke Mewburn and the NetBSD community. Later
|
|
it was imported into &os;. Its name refers to the location
|
|
of system scripts for individual services, which is in
|
|
<filename>/etc/rc.d</filename>. Soon we
|
|
will learn about more components of the <filename>rc.d</filename>
|
|
system and see how the individual scripts are invoked.</para>
|
|
|
|
<para>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 &man.sh.1; 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 &man.sh.1; functions and collected in
|
|
<filename>/etc/rc.subr</filename>. Now a typical script can
|
|
be just a few lines' worth of &man.sh.1; code. Finally, an
|
|
important part of the <filename>rc.d</filename> framework is
|
|
&man.rcorder.8;, 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.</para>
|
|
|
|
<para>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.</para>
|
|
|
|
<para>There are prerequisites to understanding this article.
|
|
First of all, you should be familiar with the &man.sh.1;
|
|
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
|
|
&man.rc.8;.</para>
|
|
|
|
<para>This article focuses on the &os; 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.</para>
|
|
</sect1>
|
|
|
|
<sect1 id="rcng-task">
|
|
<title>Outlining the task</title>
|
|
|
|
<para>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:
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Is the service mandatory or optional?</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Will the script serve a single program, e.g.,
|
|
a daemon, or perform more complex actions?</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Which other services will our service depend on,
|
|
and vice versa?</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>From the examples that follow we will see why it is
|
|
important to know the answers to these questions.</para>
|
|
|
|
<sect1 id="rcng-dummy">
|
|
<title>A dummy script</title>
|
|
|
|
<para>The following script just emits a message each time the
|
|
system boots up:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>#!/bin/sh<co id="rcng-dummy-shebang">
|
|
|
|
. /etc/rc.subr<co id="rcng-dummy-include">
|
|
|
|
name="dummy"<co id="rcng-dummy-name">
|
|
start_cmd="${name}_start"<co id="rcng-dummy-startcmd">
|
|
stop_cmd=":"<co id="rcng-dummy-stopcmd">
|
|
|
|
dummy_start()<co id="rcng-dummy-startfn">
|
|
{
|
|
echo "Nothing started."
|
|
}
|
|
|
|
load_rc_config $name<co id="rcng-dummy-loadconfig">
|
|
run_rc_command "$1"<co id="rcng-dummy-runcommand"></programlisting>
|
|
</informalexample>
|
|
|
|
<para>Things to note are:</para>
|
|
|
|
<calloutlist>
|
|
<callout arearefs="rcng-dummy-shebang">
|
|
<para>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 &man.chmod.1;.)
|
|
For example, a system admin can run our script manually,
|
|
from the command line:</para>
|
|
|
|
<screen>&prompt.root; <userinput>/etc/rc.d/dummy start</userinput></screen>
|
|
|
|
<note>
|
|
<para>In order to be properly managed by the
|
|
<filename>rc.d</filename> framework, its scripts need
|
|
to be written in the &man.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 <filename>/usr/sbin</filename>
|
|
(for the system) or <filename>/usr/local/sbin</filename>
|
|
(for ports) and call it from a &man.sh.1; script in the
|
|
appropriate <filename>rc.d</filename> directory.</para>
|
|
</note>
|
|
|
|
<tip>
|
|
<para>If you would like to learn the details of why
|
|
<filename>rc.d</filename> scripts must be written in
|
|
the &man.sh.1; 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>.</para>
|
|
</tip>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-dummy-include">
|
|
<para>In <filename>/etc/rc.subr</filename>, a number of
|
|
&man.sh.1; functions are defined for an <filename>rc.d</filename>
|
|
script to use. The functions are documented in
|
|
&man.rc.subr.8;. While it is theoretically possible to
|
|
write an <filename>rc.d</filename> script without ever
|
|
using &man.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 &man.rc.subr.8; in
|
|
<filename>rc.d</filename> scripts. We are not going to
|
|
be an exception.</para>
|
|
|
|
<para>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 &man.rc.subr.8;
|
|
functions so that &man.sh.1; has an opportunity to learn
|
|
the functions. The preferred style is to source
|
|
<filename>/etc/rc.subr</filename> first of all.</para>
|
|
|
|
<note>
|
|
<para>Some useful functions related to networking
|
|
are provided by another include file,
|
|
<filename>/etc/network.subr</filename>.</para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-dummy-name">
|
|
<para><anchor id="name-var">The mandatory variable
|
|
<envar>name</envar> specifies the name of our script. It
|
|
is required by &man.rc.subr.8;. That is, each
|
|
<filename>rc.d</filename> script <emphasis>must</emphasis>
|
|
set <envar>name</envar> before it calls &man.rc.subr.8;
|
|
functions.</para>
|
|
|
|
<para>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.</para>
|
|
|
|
<note>
|
|
<para>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
|
|
&man.sh.1; metacharacters in them, while in certain
|
|
cases you will need single quotes to prevent any
|
|
interpretation of the value by &man.sh.1;. A programmer
|
|
should be able to tell the language syntax from style
|
|
conventions and use both of them wisely.</para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-dummy-startcmd">
|
|
<para>The main idea behind &man.rc.subr.8; is that an
|
|
<filename>rc.d</filename> script provides handlers, or
|
|
methods, for &man.rc.subr.8; 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 &man.sh.1; 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 &man.rc.subr.8; provides default methods
|
|
for the standard arguments.</para>
|
|
|
|
<note>
|
|
<para>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.</para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-dummy-stopcmd">
|
|
<para>We should keep in mind that &man.rc.subr.8; provides
|
|
default methods for the standard arguments. Consequently,
|
|
we must override a standard method with a no-op &man.sh.1;
|
|
expression if we want it to do nothing.</para>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-dummy-startfn">
|
|
<para>The body of a sophisticated method can be implemented
|
|
as a function. It is a good idea to make the function
|
|
name meaningful.</para>
|
|
|
|
<important>
|
|
<para>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 &man.rc.subr.8; or another common include
|
|
file.</para>
|
|
</important>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-dummy-loadconfig">
|
|
<para>This call to &man.rc.subr.8; loads &man.rc.conf.5;
|
|
variables. Our script makes no use of them yet, but it
|
|
still is recommended to load &man.rc.conf.5; because there
|
|
can be &man.rc.conf.5; variables controlling &man.rc.subr.8;
|
|
itself.</para>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-dummy-runcommand">
|
|
<para>Usually this is the last command in an
|
|
<filename>rc.d</filename> script. It invokes the
|
|
&man.rc.subr.8; machinery to perform the requested action
|
|
using the variables and methods our script has provided.</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</sect1>
|
|
|
|
<sect1 id="rcng-confdummy">
|
|
<title>A configurable dummy script</title>
|
|
|
|
<para>Now let us add some controls to our dummy script. As you
|
|
may know, <filename>rc.d</filename> scripts are controlled
|
|
with &man.rc.conf.5;. Fortunately, &man.rc.subr.8; hides all
|
|
the complications from us. The following script uses
|
|
&man.rc.conf.5; via &man.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 <filename>rc.d</filename> script can just
|
|
support enabling and disabling its service. On the other
|
|
hand, a mandatory <filename>rc.d</filename> script can have
|
|
configuration variables. We will do both things in the same
|
|
script though:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>#!/bin/sh
|
|
|
|
. /etc/rc.subr
|
|
|
|
name="dummy"
|
|
rcvar=`set_rcvar`<co id="rcng-confdummy-rcvar">
|
|
start_cmd="${name}_start"
|
|
stop_cmd=":"
|
|
|
|
load_rc_config $name<co id="rcng-confdummy-loadconfig">
|
|
eval "${rcvar}=\${${rcvar}:-'NO'}"<co id="rcng-confdummy-enable">
|
|
dummy_msg=${dummy_msg:-"Nothing started."}<co id="rcng-confdummy-opt">
|
|
|
|
dummy_start()
|
|
{
|
|
echo "$dummy_msg"<co id="rcng-confdummy-msg">
|
|
}
|
|
|
|
run_rc_command "$1"</programlisting>
|
|
</informalexample>
|
|
|
|
<para>What changed in this example?</para>
|
|
|
|
<calloutlist>
|
|
<callout arearefs="rcng-confdummy-rcvar">
|
|
<para>The variable <envar>rcvar</envar> specifies
|
|
the name of the ON/OFF knob variable. The reason to
|
|
obtain the variable name from &man.rc.subr.8; by calling
|
|
<function>set_rcvar</function> is that different operating
|
|
systems adopted different conventions for it. Namely,
|
|
&os; sticks to the
|
|
<envar>${name}_enable</envar>
|
|
scheme while NetBSD uses just
|
|
<envar>${name}</envar> variables in its &man.rc.conf.5;.
|
|
For example, our script will be controlled by
|
|
<envar>dummy_enable</envar> in &os; and by <envar>dummy</envar>
|
|
in NetBSD.</para>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-confdummy-loadconfig">
|
|
<para>Now <function>load_rc_config</function> is invoked
|
|
earlier in the script, before any &man.rc.conf.5; variables
|
|
are accessed.</para>
|
|
|
|
<note>
|
|
<para>While examining <filename>rc.d</filename> scripts,
|
|
keep in mind that &man.sh.1; defers the evaluation of
|
|
expressions in a function until the latter is called.
|
|
Therefore it is not an error to invoke
|
|
<function>load_rc_config</function> as late as just
|
|
before <function>run_rc_command</function> and still
|
|
access &man.rc.conf.5; variables from the method functions
|
|
exported to <function>run_rc_command</function>. This
|
|
is because the method functions are to be called by
|
|
<function>run_rc_command</function>, which is invoked
|
|
<emphasis>after</emphasis>
|
|
<function>load_rc_config</function>.</para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-confdummy-enable">
|
|
<para>A warning will be emitted by
|
|
<function>run_rc_command</function> if <envar>rcvar</envar>
|
|
itself is set, but the indicated knob variable is unset.
|
|
If your <filename>rc.d</filename> script is for the base
|
|
system, you should add a default setting for the knob to
|
|
<filename>/etc/defaults/rc.conf</filename> and document
|
|
it in &man.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.</para>
|
|
|
|
<note>
|
|
<para>You can make &man.rc.subr.8; act as though the knob
|
|
is set to <literal>ON</literal>, irrespective of its
|
|
current setting, by prefixing the argument to the script
|
|
with <literal>one</literal> or <literal>force</literal>,
|
|
as in <option>onestart</option> or <option>forcestop</option>.
|
|
Keep in mind though that <literal>force</literal> has
|
|
other dangerous effects we will touch upon below, while
|
|
<literal>one</literal> just overrides the ON/OFF knob.
|
|
E.g., assume that <envar>dummy_enable</envar> is
|
|
<literal>OFF</literal>. The following command will run
|
|
the <option>start</option> method in spite of the
|
|
setting:</para>
|
|
|
|
<screen>&prompt.root; <userinput>/etc/rc.d/dummy onestart</userinput></screen>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-confdummy-opt">
|
|
<para>Now the message to be shown at boot time is no
|
|
longer hard-coded in the script. It is specified by an
|
|
&man.rc.conf.5; variable named <envar>dummy_msg</envar>.
|
|
This is a trivial example of how &man.rc.conf.5; variables
|
|
can control an <filename>rc.d</filename> script.</para>
|
|
|
|
<important>
|
|
<para>The names of all &man.rc.conf.5; variables used
|
|
exclusively by our script <emphasis>must</emphasis>
|
|
have the same prefix: <envar>${name}</envar>. For
|
|
example: <envar>dummy_mode</envar>,
|
|
<envar>dummy_state_file</envar>, and so on.</para>
|
|
</important>
|
|
|
|
<note>
|
|
<para>While it is possible to use a shorter name internally,
|
|
e.g., just <envar>msg</envar>, adding the unique prefix
|
|
<envar>${name}</envar> to all global names introduced by
|
|
our script will save us from possible
|
|
collisions with the &man.rc.subr.8; namespace.</para>
|
|
|
|
<para>As long as an &man.rc.conf.5; variable and its
|
|
internal equivalent are the same, we can use a more
|
|
compact expression to set the default value:</para>
|
|
|
|
<programlisting>: ${dummy_msg:="Nothing started."}</programlisting>
|
|
|
|
<para>The current style is to use the more verbose form
|
|
though.</para>
|
|
|
|
<para>As a rule, <filename>rc.d</filename> scripts of the
|
|
base system need not provide defaults for their
|
|
&man.rc.conf.5; variables because the defaults should
|
|
be set in <filename>/etc/defaults/rc.conf</filename>
|
|
instead. On the other hand, <filename>rc.d</filename>
|
|
scripts for ports should provide the defaults as shown
|
|
in the example.</para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-confdummy-msg">
|
|
<para>Here we use <envar>dummy_msg</envar> to actually
|
|
control our script, i.e., to emit a variable message.</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</sect1>
|
|
|
|
<sect1 id="rcng-daemon">
|
|
<title>Startup and shutdown of a simple daemon</title>
|
|
|
|
<para>We said earlier that &man.rc.subr.8; could provide default
|
|
methods. Obviously, such defaults cannot be too general.
|
|
They are suited for the common case of starting and shutting
|
|
down a simple daemon program. Let us assume now that we need
|
|
to write an <filename>rc.d</filename> script for such a daemon
|
|
called <command>mumbled</command>. Here it is:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>#!/bin/sh
|
|
|
|
. /etc/rc.subr
|
|
|
|
name="mumbled"
|
|
rcvar=`set_rcvar`
|
|
command="/usr/sbin/${name}"<co id="rcng-daemon-basic-cmd">
|
|
|
|
load_rc_config $name
|
|
run_rc_command "$1"</programlisting>
|
|
</informalexample>
|
|
|
|
<para>Pleasingly simple, isn't it? Let us examine our little
|
|
script. The only new thing to note is as follows:</para>
|
|
|
|
<calloutlist>
|
|
<callout arearefs="rcng-daemon-basic-cmd">
|
|
<para>The <envar>command</envar> variable is meaningful to
|
|
&man.rc.subr.8;. If it is set, &man.rc.subr.8; will act
|
|
according to the scenario of serving a conventional daemon.
|
|
In particular, the default methods will be provided for
|
|
such arguments: <option>start</option>, <option>stop</option>,
|
|
<option>restart</option>, <option>poll</option>, and
|
|
<option>status</option>.</para>
|
|
|
|
<para>The daemon will be started by running
|
|
<envar>$command</envar> with command-line flags specified
|
|
by <envar>$mumbled_flags</envar>. Thus all the input
|
|
data for the default <option>start</option> method are
|
|
available in the variables set by our script. Unlike
|
|
<option>start</option>, other methods may require additional
|
|
information about the process started. For instance,
|
|
<option>stop</option> must know the PID of the process
|
|
to terminate it. In the present case, &man.rc.subr.8;
|
|
will scan through the list of all processes, looking for
|
|
a process with its name equal to <envar>$procname</envar>.
|
|
The latter is another variable of meaning to &man.rc.subr.8;,
|
|
and its value defaults to that of <envar>command</envar>.
|
|
In other words, when we set <envar>command</envar>,
|
|
<envar>procname</envar> is effectively set to the same
|
|
value. This enables our script to kill the daemon and
|
|
to check if it is running in the first place.</para>
|
|
|
|
<note>
|
|
<para>Some programs are in fact executable scripts. The
|
|
system runs such a script by starting its interpreter
|
|
and passing the name of the script to it as a command-line
|
|
argument. This is reflected in the list of processes,
|
|
which can confuse &man.rc.subr.8;. You should additionally
|
|
set <envar>command_interpreter</envar> to let &man.rc.subr.8;
|
|
know the actual name of the process if <envar>$command</envar>
|
|
is a script.</para>
|
|
|
|
<para>For each <filename>rc.d</filename> script, there
|
|
is an optional &man.rc.conf.5; variable that takes
|
|
precedence over <envar>command</envar>. Its name is
|
|
constructed as follows: <envar>${name}_program</envar>,
|
|
where <envar>name</envar> is the mandatory variable we
|
|
discussed <link linkend="name-var">earlier</link>.
|
|
E.g., in this case it will be <envar>mumbled_program</envar>.
|
|
It is &man.rc.subr.8; that arranges
|
|
<envar>${name}_program</envar> to override
|
|
<envar>command</envar>.</para>
|
|
|
|
<para>Of course, &man.sh.1; will permit you to set
|
|
<envar>${name}_program</envar> from &man.rc.conf.5; or
|
|
the script itself even if <envar>command</envar> is
|
|
unset. In that case, the special properties of
|
|
<envar>${name}_program</envar> are lost, and it becomes
|
|
an ordinary variable your script can use for its own
|
|
purposes. However, the sole use of
|
|
<envar>${name}_program</envar> is discouraged because
|
|
using it together with <envar>command</envar> became
|
|
an idiom of <filename>rc.d</filename> scripting.</para>
|
|
</note>
|
|
|
|
<para>For more detailed information on default methods,
|
|
refer to &man.rc.subr.8;.</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</sect1>
|
|
|
|
<sect1 id="rcng-daemon-adv">
|
|
<title>Startup and shutdown of an advanced daemon</title>
|
|
|
|
<para>Let us add some meat onto the bones of the previous
|
|
script and make it more complex and featureful. The default
|
|
methods can do a good job for us, but we may need some of
|
|
their aspects tweaked. Now we will learn how to tune the
|
|
default methods to our needs.</para>
|
|
|
|
<informalexample>
|
|
<programlisting>#!/bin/sh
|
|
|
|
. /etc/rc.subr
|
|
|
|
name="mumbled"
|
|
rcvar=`set_rcvar`
|
|
|
|
command="/usr/sbin/${name}"
|
|
command_args="mock arguments > /dev/null 2>&1"<co id="rcng-daemon-adv-args">
|
|
|
|
pidfile="/var/run/${name}.pid"<co id="rcng-daemon-adv-pid">
|
|
|
|
required_files="/etc/${name}.conf /usr/share/misc/${name}.rules"<co id="rcng-daemon-adv-reqfiles">
|
|
|
|
sig_reload="USR1"<co id="rcng-daemon-adv-sig">
|
|
|
|
start_precmd="${name}_prestart"<co id="rcng-daemon-adv-precmd">
|
|
stop_postcmd="echo Bye-bye"<co id="rcng-daemon-adv-postcmd">
|
|
|
|
extra_commands="reload plugh xyzzy"<co id="rcng-daemon-adv-extra">
|
|
|
|
plugh_cmd="mumpled_plugh"<co id="rcng-daemon-adv-methods">
|
|
xyzzy_cmd="echo 'Nothing happens.'"
|
|
|
|
mumbled_prestart()
|
|
{
|
|
if checkyesno mumbled_smart; then<co id="rcng-daemon-adv-yn">
|
|
rc_flags="-o smart ${rc_flags}"<co id="rcng-daemon-adv-rcflags">
|
|
fi
|
|
case "$mumbled_mode" in
|
|
foo)
|
|
rc_flags="-frotz ${rc_flags}"
|
|
;;
|
|
bar)
|
|
rc_flags="-baz ${rc_flags}"
|
|
;;
|
|
*)
|
|
warn "Invalid value for mumbled_mode"<co id="rcng-daemon-adv-warn">
|
|
return 1<co id="rcng-daemon-adv-preret">
|
|
;;
|
|
esac
|
|
run_rc_command xyzzy<co id="rcng-daemon-adv-run">
|
|
return 0
|
|
}
|
|
|
|
mumbled_plugh()<co id="rcng-daemon-adv-plugh">
|
|
{
|
|
echo 'A hollow voice says "plugh".'
|
|
}
|
|
|
|
load_rc_config $name
|
|
run_rc_command "$1"</programlisting>
|
|
</informalexample>
|
|
|
|
<calloutlist>
|
|
<callout arearefs="rcng-daemon-adv-args">
|
|
<para>Additional arguments to <envar>$command</envar> can
|
|
be passed in <envar>command_args</envar>. They will be
|
|
added to the command line after <envar>$mumbled_flags</envar>.
|
|
Since the final command line is passed to <command>eval</command>
|
|
for its actual execution, input and output redirections
|
|
can be specified in <envar>command_args</envar>.</para>
|
|
|
|
<note>
|
|
<para><emphasis>Never</emphasis> include dashed options,
|
|
like <option>-X</option> or <option>--foo</option>, in
|
|
<envar>command_args</envar>.
|
|
The contents of <envar>command_args</envar> will
|
|
appear at the end of the final command line, hence
|
|
they are likely to follow arguments present in
|
|
<envar>${name}_flags</envar>; but most commands will
|
|
not recognize dashed options after ordinary arguments.
|
|
A better way of passing additional options
|
|
to <envar>$command</envar> is to add them
|
|
to the beginning of <envar>${name}_flags</envar>.
|
|
Another way is to modify <envar>rc_flags</envar> <link
|
|
linkend="rc-flags">as shown later</link>.</para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-daemon-adv-pid">
|
|
<para>A good-mannered daemon should create a
|
|
<emphasis>pidfile</emphasis> so that its process can be
|
|
found more easily and reliably. The variable
|
|
<envar>pidfile</envar>, if set, tells &man.rc.subr.8;
|
|
where it can find the pidfile for its default methods to
|
|
use.</para>
|
|
|
|
<note>
|
|
<para>In fact, &man.rc.subr.8; will also use the pidfile
|
|
to see if the daemon is already running before starting
|
|
it. This check can be skipped by using the
|
|
<option>faststart</option> argument.</para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-daemon-adv-reqfiles">
|
|
<para>If the daemon cannot run unless certain files exist,
|
|
just list them in <envar>required_files</envar>, and
|
|
&man.rc.subr.8; will check that those files do exist
|
|
before starting the daemon. There also are
|
|
<envar>required_dirs</envar> and <envar>required_vars</envar>
|
|
for directories and environment variables, respectively.
|
|
They all are described in detail in &man.rc.subr.8;.</para>
|
|
|
|
<note>
|
|
<para>The default method from &man.rc.subr.8; can be
|
|
forced to skip the prerequisite checks by using
|
|
<option>forcestart</option> as the argument to the
|
|
script.</para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-daemon-adv-sig">
|
|
<para>We can customize signals to send to the daemon in
|
|
case they differ from the well-known ones. In particular,
|
|
<envar>sig_reload</envar> specifies the signal that makes
|
|
the daemon reload its configuration; it is
|
|
<symbol>SIGHUP</symbol> by default. Another signal is
|
|
sent to stop the daemon process; the default is
|
|
<symbol>SIGTERM</symbol>, but this can be changed by
|
|
setting <envar>sig_stop</envar> appropriately.</para>
|
|
|
|
<note>
|
|
<para>The signal names should be specified to &man.rc.subr.8;
|
|
without the <literal>SIG</literal> prefix, as it is
|
|
shown in the example. The &os; version of &man.kill.1;
|
|
can recognize the <literal>SIG</literal> prefix, but
|
|
the versions from other OS types may not.</para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-daemon-adv-precmd rcng-daemon-adv-postcmd">
|
|
<para>Performing additional tasks before or after the default
|
|
methods is easy. For each command-argument supported by
|
|
our script, we can define
|
|
<envar><replaceable>argument</replaceable>_precmd</envar> and
|
|
<envar><replaceable>argument</replaceable>_postcmd</envar>.
|
|
These &man.sh.1; commands are invoked before and after
|
|
the respective method, as it is evident from their
|
|
names.</para>
|
|
|
|
<note>
|
|
<para>Overriding a default method with a custom
|
|
<envar><replaceable>argument</replaceable>_cmd</envar>
|
|
still does not prevent us from making use of
|
|
<envar><replaceable>argument</replaceable>_precmd</envar> or
|
|
<envar><replaceable>argument</replaceable>_postcmd</envar>
|
|
if we need to. In particular, the former is good for
|
|
checking custom, sophisticated conditions that should
|
|
be met before performing the command itself. Using
|
|
<envar><replaceable>argument</replaceable>_precmd</envar> along
|
|
with <envar><replaceable>argument</replaceable>_cmd</envar>
|
|
lets us logically separate the checks from the
|
|
action.</para>
|
|
|
|
<para>Do not forget that you can cram any valid &man.sh.1;
|
|
expressions into the methods, pre-, and post-commands
|
|
you define. Just invoking a function that makes the
|
|
real job is a good style in most cases, but never let
|
|
style limit your understanding of what is going on
|
|
behind the curtain.</para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-daemon-adv-extra">
|
|
<para>If we would like to implement custom arguments, which
|
|
can also be thought of as <emphasis>commands</emphasis>
|
|
to our script, we need to list them in
|
|
<envar>extra_commands</envar> and provide methods to
|
|
handle them.</para>
|
|
|
|
<note>
|
|
<para>The <option>reload</option> command is special. On
|
|
the one hand, it has a preset method in &man.rc.subr.8;.
|
|
On the other hand, <option>reload</option> is not offered
|
|
by default. The reason is that not all daemons use the
|
|
same reload mechanism and some have nothing to reload
|
|
at all. So we need to ask explicitly that the builtin
|
|
functionality be provided. We can do so via
|
|
<envar>extra_commands</envar>.</para>
|
|
|
|
<para>What do we get from the default method for
|
|
<option>reload</option>? Quite often daemons reload
|
|
their configuration upon reception of a signal —
|
|
typically, <symbol>SIGHUP</symbol>. Therefore
|
|
&man.rc.subr.8; attempts to reload the daemon by sending
|
|
a signal to it. The signal is preset to
|
|
<symbol>SIGHUP</symbol> but can be customized via
|
|
<envar>sig_reload</envar> if necessary.</para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-daemon-adv-methods rcng-daemon-adv-plugh">
|
|
<para>Our script supports two non-standard commands,
|
|
<option>plugh</option> and <option>xyzzy</option>. We
|
|
saw them listed in <envar>extra_commands</envar>, and now
|
|
it is time to provide methods for them. The method for
|
|
<option>xyzzy</option> is just inlined while that for
|
|
<option>plugh</option> is implemented as the
|
|
<function>mumbled_plugh</function> function.</para>
|
|
|
|
<para>Non-standard commands are not invoked during startup
|
|
or shutdown. Usually they are for the system admin's
|
|
convenience. They can also be used from other subsystems,
|
|
e.g., &man.devd.8; if specified in &man.devd.conf.5;.</para>
|
|
|
|
<para>The full list of available commands can be found in
|
|
the usage line printed by &man.rc.subr.8; when the script
|
|
is invoked without arguments. For example, here is the
|
|
usage line from the script under study:</para>
|
|
|
|
<screen>&prompt.root; <userinput>/etc/rc.d/mumbled</userinput>
|
|
Usage: /etc/rc.d/mumbled [fast|force|one](start|stop|restart|rcvar|reload|plugh|xyzzy|status|poll)</screen>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-daemon-adv-run">
|
|
<para>A script can invoke its own standard or non-standard
|
|
commands if needed. This may look similar to calling
|
|
functions, but we know that commands and shell functions
|
|
are not always the same thing. For instance,
|
|
<command>xyzzy</command> is not implemented as a function
|
|
here. In addition, there can be a pre-command and
|
|
post-command, which should be invoked orderly. So the
|
|
proper way for a script to run its own command is by means
|
|
of &man.rc.subr.8;, as shown in the example.</para>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-daemon-adv-yn">
|
|
<para>A handy function named <function>checkyesno</function>
|
|
is provided by &man.rc.subr.8;. It takes a variable name
|
|
as its argument and returns a zero exit code if and only
|
|
if the variable is set to <literal>YES</literal>, or
|
|
<literal>TRUE</literal>, or <literal>ON</literal>, or
|
|
<literal>1</literal>, case insensitive; a non-zero exit
|
|
code is returned otherwise. In the latter case, the
|
|
function tests the variable for being set to
|
|
<literal>NO</literal>, <literal>FALSE</literal>,
|
|
<literal>OFF</literal>, or <literal>0</literal>, case
|
|
insensitive; it prints a warning message if the variable
|
|
contains anything else, i.e., junk.</para>
|
|
|
|
<para>Keep in mind that for &man.sh.1; a zero exit code
|
|
means true and a non-zero exit code means false.</para>
|
|
|
|
<important>
|
|
<para>The <function>checkyesno</function> function takes
|
|
a <emphasis>variable name</emphasis>. Do not pass the
|
|
expanded <emphasis>value</emphasis> of a variable to
|
|
it; it will not work as expected.</para>
|
|
|
|
<para>The following is the correct usage of
|
|
<function>checkyesno</function>:</para>
|
|
|
|
<programlisting>if checkyesno mumbled_enable; then
|
|
foo
|
|
fi</programlisting>
|
|
|
|
<para>On the contrary, calling <function>checkyesno</function>
|
|
as shown below will not work — at least not as
|
|
expected:</para>
|
|
|
|
<programlisting>if checkyesno "${mumbled_enable}"; then
|
|
foo
|
|
fi</programlisting>
|
|
</important>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-daemon-adv-rcflags">
|
|
<para><anchor id="rc-flags">We can affect the flags to be
|
|
passed to <envar>$command</envar> by modifying
|
|
<envar>rc_flags</envar> in <envar>$start_precmd</envar>.</para>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-daemon-adv-warn">
|
|
<para>In certain cases we may need to emit an important
|
|
message that should go to <application>syslog</application>
|
|
as well. This can be done easily with the following
|
|
&man.rc.subr.8; functions: <function>debug</function>,
|
|
<function>info</function>, <function>warn</function>, and
|
|
<function>err</function>. The latter function then exits
|
|
the script with the code specified.</para>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-daemon-adv-preret">
|
|
<para>The exit codes from methods and their pre-commands
|
|
are not just ignored by default. If
|
|
<envar><replaceable>argument</replaceable>_precmd</envar> returns
|
|
a non-zero exit code, the main method will not be performed.
|
|
In turn,
|
|
<envar><replaceable>argument</replaceable>_postcmd</envar> will
|
|
not be invoked unless the main method returns a zero exit
|
|
code.
|
|
|
|
<note>
|
|
<para>However, &man.rc.subr.8; can be instructed from the
|
|
command line to ignore those exit codes and invoke all
|
|
commands anyway by prefixing an argument with
|
|
<literal>force</literal>, as in
|
|
<option>forcestart</option>.</para>
|
|
</note>
|
|
</callout>
|
|
</calloutlist>
|
|
</sect1>
|
|
|
|
<sect1 id="rcng-hookup">
|
|
<title>Connecting a script to the rc.d framework</title>
|
|
|
|
<para>After a script has been written, it needs to be integrated
|
|
into <filename>rc.d</filename>. The crucial step is to install
|
|
the script in <filename>/etc/rc.d</filename> (for the base
|
|
system) or <filename>/usr/local/etc/rc.d</filename> (for
|
|
ports). Both <<filename>bsd.prog.mk</filename>> and
|
|
<<filename>bsd.port.mk</filename>> provide convenient
|
|
hooks for that, and usually you do not have to worry about
|
|
the proper ownership and mode. System scripts should be
|
|
installed from <filename>src/etc/rc.d</filename> through the
|
|
<filename>Makefile</filename> found there. Port scripts can
|
|
be installed using <makevar>USE_RC_SUBR</makevar> as described
|
|
<ulink url="&url.books.porters-handbook;/rc-scripts.html">in
|
|
the Porter's Handbook</ulink>.</para>
|
|
|
|
<para>However, we should consider beforehand the place of
|
|
our script in the system startup sequence. The service handled
|
|
by our script is likely to depend on other services. For
|
|
instance, a network daemon cannot function without the network
|
|
interfaces and routing up and running. Even if a service
|
|
seems to demand nothing, it can hardly start before the basic
|
|
filesystems have been checked and mounted.</para>
|
|
|
|
<para>We mentioned &man.rcorder.8; already. Now it is time to
|
|
have a close look at it. In a nutshell, &man.rcorder.8; takes
|
|
a set of files, examines their contents, and prints a
|
|
dependency-ordered list of files from the set to
|
|
<varname>stdout</varname>. The point is to keep dependency
|
|
information <emphasis>inside</emphasis> the files so that
|
|
each file can speak for itself only. A file can specify the
|
|
following information:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>the names of the <quote>conditions</quote> (which means
|
|
services to us) it <emphasis>provides</emphasis>;</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>the names of the <quote>conditions</quote>
|
|
it <emphasis>requires</emphasis>;</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>the names of the <quote>conditions</quote> this file
|
|
should run <emphasis>before</emphasis>;</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>additional <emphasis>keywords</emphasis> that can be
|
|
used to select a subset from the whole set of files
|
|
(&man.rcorder.8; can be instructed via options to include
|
|
or omit the files having particular keywords listed.)</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>It is no surprise that &man.rcorder.8; can handle only
|
|
text files with a syntax close to that of &man.sh.1;. That
|
|
is, special lines understood by &man.rcorder.8; look like
|
|
&man.sh.1; comments. The syntax of such special lines is
|
|
rather rigid to simplify their processing. See &man.rcorder.8;
|
|
for details.</para>
|
|
|
|
<para>Besides using &man.rcorder.8; special lines, a script can
|
|
insist on its dependency upon another service by just starting
|
|
it forcibly. This can be needed when the other service is
|
|
optional and will not start by itself because the system admin
|
|
has disabled it mistakenly in &man.rc.conf.5;.</para>
|
|
|
|
<para>With this general knowledge in mind, let us consider the
|
|
simple daemon script enhanced with dependency stuff:
|
|
|
|
<informalexample>
|
|
<programlisting>#!/bin/sh
|
|
|
|
# PROVIDE: mumbled oldmumble <co id="rcng-hookup-provide">
|
|
# REQUIRE: DAEMON cleanvar frotz<co id="rcng-hookup-require">
|
|
# BEFORE: LOGIN<co id="rcng-hookup-before">
|
|
# KEYWORD: nojail shutdown<co id="rcng-hookup-keyword">
|
|
|
|
. /etc/rc.subr
|
|
|
|
name="mumbled"
|
|
rcvar=`set_rcvar`
|
|
command="/usr/sbin/${name}"
|
|
start_precmd="${name}_prestart"
|
|
|
|
mumbled_prestart()
|
|
{
|
|
if ! checkyesno frotz_enable && \
|
|
! /etc/rc.d/frotz forcestatus 1>/dev/null 2>&1; then
|
|
force_depend frotz || return 1<co id="rcng-hookup-force">
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
load_rc_config $name
|
|
run_rc_command "$1"</programlisting>
|
|
</informalexample>
|
|
|
|
<para>As before, detailed analysis follows:</para>
|
|
|
|
<calloutlist>
|
|
<callout arearefs="rcng-hookup-provide">
|
|
<para>That line declares the names of <quote>conditions</quote>
|
|
our script provides. Now other scripts can record a
|
|
dependency on our script by those names.</para>
|
|
|
|
<note>
|
|
<para>Usually a script specifies a single condition
|
|
provided. However, nothing prevents us from listing
|
|
several conditions there, e.g., for compatibility
|
|
reasons.</para>
|
|
|
|
<para>In any case, the name of the main, or the only,
|
|
<literal>PROVIDE:</literal> condition should be the
|
|
same as <envar>${name}</envar>.</para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-hookup-require rcng-hookup-before">
|
|
<para>So our script indicates which <quote>conditions</quote>
|
|
provided by other scripts it depends on. According to
|
|
the lines, our script asks &man.rcorder.8; to put it after
|
|
the script(s) providing <filename>DAEMON</filename> and
|
|
<filename>cleanvar</filename>, but before that providing
|
|
<filename>LOGIN</filename>.</para>
|
|
|
|
<note>
|
|
<para>The <literal>BEFORE:</literal> line should not be
|
|
abused to work around an incomplete dependency list in
|
|
the other script. The appropriate case for using
|
|
<literal>BEFORE:</literal> is when the other script
|
|
does not care about ours, but our script can do its
|
|
task better if run before the other one. A typical
|
|
real-life example is the network interfaces vs. the
|
|
firewall: While the interfaces do not depend on the
|
|
firewall in doing their job, the system security will
|
|
benefit from the firewall being ready before there is
|
|
any network traffic.</para>
|
|
|
|
<para>Besides conditions corresponding to a single service
|
|
each, there are meta-conditions and their
|
|
<quote>placeholder</quote> scripts used to ensure that
|
|
certain groups of operations are performed before others.
|
|
These are denoted by
|
|
<filename><replaceable>UPPERCASE</replaceable></filename>
|
|
names. Their list and purposes can be found in
|
|
&man.rc.8;.</para>
|
|
|
|
<para>Keep in mind that putting a service name in the
|
|
<literal>REQUIRE:</literal> line does not guarantee
|
|
that the service will actually be running by the time
|
|
our script starts. The required service may fail to
|
|
start or just be disabled in &man.rc.conf.5;. Obviously,
|
|
&man.rcorder.8; cannot track such details, and &man.rc.8;
|
|
will not do that either. Consequently, the application
|
|
started by our script should be able to cope with any
|
|
required services being unavailable. In certain cases,
|
|
we can help it as discussed <link
|
|
linkend="forcedep">below.</link></para>
|
|
</note>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-hookup-keyword">
|
|
<para><anchor id="keywords">There are several keywords used
|
|
in &os;:</para>
|
|
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term><literal>nojail</literal></term>
|
|
|
|
<listitem>
|
|
<para>The service is not for &man.jail.8; environment.
|
|
The automatic startup and shutdown procedures will
|
|
ignore the script if inside a jail.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><literal>nostart</literal></term>
|
|
|
|
<listitem>
|
|
<para>The service is to be started manually or not
|
|
started at all. The automatic startup procedure
|
|
will ignore the script. In conjunction with the
|
|
<literal>shutdown</literal> keyword, this can be
|
|
used to write scripts that do something only at
|
|
system shutdown.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><literal>shutdown</literal></term>
|
|
|
|
<listitem>
|
|
<para>The script wants to be run during system
|
|
shutdown. Without the keyword listed,
|
|
<filename>/etc/rc.shutdown</filename> would ignore
|
|
it for faster shutdown.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
</callout>
|
|
|
|
<callout arearefs="rcng-hookup-force">
|
|
<para><anchor id="forcedep">To begin with,
|
|
<function>force_depend</function> should be used with
|
|
much care. It is generally better to revise the hierarchy
|
|
of configuration variables for your <filename>rc.d</filename>
|
|
scripts if they are interdependent.</para>
|
|
|
|
<para>If you still cannot do without
|
|
<function>force_depend</function>, the example offers an
|
|
idiom of how to invoke it conditionally. In the example,
|
|
our <command>mumbled</command> daemon requires that another
|
|
one, <command>frotz</command>, be started in advance.
|
|
However, <command>frotz</command> is optional, too; and
|
|
&man.rcorder.8; knows nothing about such details.
|
|
Fortunately, our script has access to all &man.rc.conf.5;
|
|
variables. If <envar>frotz_enable</envar> is true, we
|
|
hope for the best and rely on <filename>rc.d</filename>
|
|
to have started <command>frotz</command>. Otherwise we
|
|
forcibly check the status of <command>frotz</command>.
|
|
Finally, we enforce our dependency on <command>frotz</command>
|
|
if it is found to be not running. A warning message will
|
|
be emitted by <function>force_depend</function> because
|
|
it should be invoked only if a misconfiguration has been
|
|
detected.</para>
|
|
</callout>
|
|
</calloutlist>
|
|
</sect1>
|
|
|
|
<sect1 id="rcng-furthur">
|
|
<title>Further reading</title>
|
|
|
|
<para><anchor id="lukem"><ulink
|
|
url="http://www.mewburn.net/luke/papers/rc.d.pdf">The original
|
|
article by Luke Mewburn</ulink> offers a general overview of
|
|
<filename>rc.d</filename> and detailed rationale for its
|
|
design decisions. It provides insight on the whole
|
|
<filename>rc.d</filename> framework and its place in a modern
|
|
BSD operating system.</para>
|
|
|
|
<para><anchor id="manpages">The manual pages &man.rc.8;,
|
|
&man.rc.subr.8;, and &man.rcorder.8; document the
|
|
<filename>rc.d</filename> components in great detail. You
|
|
cannot fully use the <filename>rc.d</filename> power without
|
|
studying the manual pages and referring to them while writing
|
|
your own scripts.</para>
|
|
|
|
<para>The major source of working, real-life examples is
|
|
<filename>/etc/rc.d</filename> in a live system. Its contents
|
|
are easy and pleasant to read because most rough corners are
|
|
hidden deep in &man.rc.subr.8;. Keep in mind though that the
|
|
<filename>/etc/rc.d</filename> scripts were not written by
|
|
angels, so they might suffer from bugs and suboptimal design
|
|
decisions. Now you can improve them!</para>
|
|
</sect1>
|
|
</article>
|