FreeBSD uses the init system, and system services must be made as rc.d scripts.
You can find more detailed information and examples in the handbook: Practical rc.d scripting.
¶CLI options choice for daemons
Find below the options we normally use for any /etc/rc.d
script as
daemon. See more options by in the terminal issuing: man daemon
-f
: Redirect standard input, standard output and standard error to
/dev/null
. When this option is used together with any of the options
related to file or syslog
output, the standard file descriptors are
first redirected to /dev/null
, then stdout
and/or stderr
is
redirected to a file or to syslog
as specified by the other options.
-S
: Enable syslog
output. This is implicitly applied if other
syslog
parameters are provided. The default values are daemon
,
notice
, and daemon
for facility, priority, and tag, respectively.
-P
: Write the ID of the daemon process into the file with given name
using the pidfile
functionality. The program is executed in a spawned
child process while the daemon waits until it terminates to keep the
supervisor_pidfile
locked and removes it after the process exits. The
supervisor_pidfile
owner is the user who runs the daemon regardless of
whether the -u
option is used or not.
-r
: Supervise and restart the program after a one-second delay if it
has been terminated. Connecting a script to the rc.d framework
In a nutshell, rcorder
takes a set of files, examines their contents,
and prints a dependency-ordered list of files from the set to stdout.
The point is to keep dependency information inside the files so that
each file can speak for itself only. A file can specify the following
information:
- the names of the “conditions” (which means services to us) it provides
with
# KEYWORD
: - the names of the “conditions” it requires with
# REQUIRE
: - the names of the “conditions” this file should run before with
# BEFORE
: - additional keywords that can be used to select a subset from the whole
set of files (
rcorder
can be instructed via options to include or omit the files having particular keywords listed.) with # KEYWORD:
As a rule of thumb, every custom made rc.d script should provide 1
daemon, and require DAEMON
and networking
to be initialized. Thus
the first lines of your rc.d script will generally look something like:
#!/bin/sh # # PROVIDE: <name of this rc.d script> # REQUIRE: DAEMON networking # KEYWORD:
¶Daemon load order
The order in which the daemons load is highly important. For this
example, our my_service
rc.d script should run as a daemon and should
be able to access the network.
This means that it should only load after DAEMON
and networking
are
loaded and running.
You can verify the load order with:
service -e
The correct load order in this case then would be:
service -e /etc/rc.d/cleanvar /etc/rc.d/ip6addrctl /etc/rc.d/netif /etc/rc.d/virecover /etc/rc.d/motd /etc/rc.d/os-release /etc/rc.d/newsyslog /etc/rc.d/syslogd /etc/rc.d/my_service /etc/rc.d/cron
¶Go applications as daemons
In the case of Go binaries, I will use the daemon in a straightforward
manner. See the example below for one of my Go applications, running as
a compiled binary. I assume
/root/internalApplications/my-service-folder
is the folder where the
service is located and should be running from:
#!/bin/sh # # PROVIDE: my_service # REQUIRE: DAEMON networking # KEYWORD: . /etc/rc.subr name="my_service" rcvar="my_service_enable" my_service_chdir="/root/internalApplications/my-service-folder" my_service_user="root" my_service_command="/root/internalApplications/my-service-folder/app" pidfile="/var/run/${name}.pid" command="/usr/sbin/daemon" command_args="-P ${pidfile} -r -f -S ${my_service_command}" load_rc_config $name : ${my_service_enable:=no} run_rc_command "$1"
¶Shell scripts as daemons
Shell scripts that run utilities can also be daemonized. See the example below I use for Jaeger:
#!/bin/sh # PROVIDE: jaeger_tracer # REQUIRE: DAEMON networking # KEYWORD: . /etc/rc.subr name="jaeger_tracer" rcvar="jaeger_tracer_enable" jaeger_tracer_user="root" pidfile="/var/run/${name}.pid" jaeger_tracer_command="/root/internalApplications/run-jaeger.sh" command="/usr/sbin/daemon" command_args="-P ${pidfile} -r -f -S ${jaeger_tracer_command}" load_rc_config $name : ${jaeger_tracer_enable:=no} run_rc_command "$1"
¶Conclusion
Once the rc.d script is created then you should make it executable with
chmod +x /etc/rc.d/my_service
and you can then use it as a system service whose output is in
/var/log/messages
.
service my_service status service my_service enable service my_service start service my_service restart service my_service stop