rc.d
scripts are used to start
services on system startup, and to give administrators a
standard way of stopping, starting and restarting the service.
Ports integrate into the system rc.d
framework. Details on its usage can be found in the
rc.d Handbook chapter. Detailed explanation of
the available commands is provided in rc(8) and
rc.subr(8). Finally, there is
an
article on practical aspects of
rc.d
scripting.
With a mythical port called
doorman
, which needs to start a
doormand
daemon. Add the following
to the Makefile
:
USE_RC_SUBR= doormand
Multiple scripts may be listed and will be installed.
Scripts must be placed in the files
subdirectory and a .in
suffix must be added
to their filename. Standard SUB_LIST
expansions will be ran against this file. Use of the
%%PREFIX%%
and
%%LOCALBASE%%
expansions is strongly
encouraged as well. More on SUB_LIST
in
the relevant
section.
As of FreeBSD 6.1-RELEASE, local
rc.d
scripts (including those installed
by ports) are included in the overall rcorder(8) of the
base system.
An example simple rc.d
script to start
the doormand daemon:
#!/bin/sh # $FreeBSD$ # # PROVIDE:doormand
# REQUIRE: LOGIN # KEYWORD: shutdown # # Add these lines to /etc/rc.conf.local or /etc/rc.conf # to enable this service: # #doormand
_enable (bool): Set to NO by default. # Set it to YES to enabledoormand
. #doormand
_config (path): Set to %%PREFIX%%/etc/doormand/doormand.cf
# by default. . /etc/rc.subr name=doormand
rcvar=doormand
_enable load_rc_config $name : ${doormand
_enable:="NO"} : ${doormand
_config="%%PREFIX%%/etc/doormand/doormand.cf
"} command=%%PREFIX%%/sbin/${name} pidfile=/var/run/${name}.pid command_args="-p $pidfile -f $doormand_config
" run_rc_command "$1"
Unless there is a very good reason to start the service earlier, or it runs as a particular user (other than root), all ports scripts must use:
REQUIRE: LOGIN
If the startup script launches a daemon that must be shutdown, the following will trigger a stop of the service on system shutdown:
KEYWORD: shutdown
If the script is not starting a persistent service this is not necessary.
For optional configuration elements the "=" style of default variable assignment is preferable to the ":=" style here, since the former sets a default value only if the variable is unset, and the latter sets one if the variable is unset or null. A user might very well include something like:
doormand
_flags=""
in their rc.conf.local
, and a
variable substitution using ":=" would
inappropriately override the user's intention. The
_enable
variable is not optional,
and must use the ":" for the default.
Before contributing a port with an
rc.d
script, and more importantly,
before committing one, please consult this
checklist to be sure that it is ready.
The devel/rclint port can check for most of these, but it is not a substitute for proper review.
If this is a new file, does it have a
.sh
extension? If so, that
must be changed to just
since file
.inrc.d
files may not end
with that extension.
Does the file have a
$FreeBSD$
tag?
Do the name of the file (minus
.in
), the
PROVIDE
line, and
$
name
all match? The file name matching
PROVIDE
makes debugging easier,
especially for rcorder(8) issues. Matching the
file name and
$
name
makes it easier to figure out which variables are
relevant in rc.conf[.local]
. It is
also a policy
for all new scripts, including those in the base
system.
Is the REQUIRE
line set to
LOGIN
? This is mandatory for scripts
that run as a non-root user. If it runs as root, is
there a good reason for it to run prior to
LOGIN
? If not, it must run after
so that local scrips can be loosely grouped to a point in
rcorder(8) after most everything in the base is
already running.
Does the script start a persistent service? If so,
it must have KEYWORD:
shutdown
.
Make sure there is no
KEYWORD: FreeBSD
present. This has
not been necessary or desirable for years. It is also
an indication that the new script was copy/pasted from
an old script, so extra caution must be given to the
review.
If the script uses an interpreted language like
perl
, python
, or
ruby
, make certain that
command_interpreter
is set
appropriately, for example, for Perl,
by adding PERL=${PERL}
to
SUB_LIST
and using
%%PERL%%
. Otherwise,
#
service
name
stop
will probably not work properly. See service(8) for more information.
Have all occurrences of
/usr/local
been replaced with
%%PREFIX%%
?
Do the default variable assignments come after
load_rc_config
?
Are there default assignments to empty strings? They should be removed, but double-check that the option is documented in the comments at the top of the file.
Are things that are set in variables actually used in the script?
Are options listed in the default
name
_flags
things that are actually mandatory? If so, they must
be in command_args
. The
-d
option is a red flag (pardon the
pun) here, since it is usually the option to
“daemonize” the process, and therefore is
actually mandatory.
must never be included in
name
_flagscommand_args
(and vice versa,
although that error is less common).
Does the script execute any code unconditionally?
This is frowned on. Usually these things must be
dealt with through a
start_precmd
.
All boolean tests must use the
checkyesno
function. No
hand-rolled tests for [Yy][Ee][Ss]
,
etc.
If there is a loop (for example, waiting for something to start) does it have a counter to terminate the loop? We do not want the boot to be stuck forever if there is an error.
Does the script create files or directories that
need specific permissions, for example, a
pid
that needs to be owned by
the user that runs the process? Rather than the
traditional touch(1)/chown(8)/chmod(1)
routine, consider using install(1) with the proper
command line arguments to do the whole procedure with
one step.
All FreeBSD documents are available for download at http://ftp.FreeBSD.org/pub/FreeBSD/doc/
Questions that are not answered by the
documentation may be
sent to <[email protected]>.
Send questions about this document to <[email protected]>.